swamp_analyzer/
def.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use crate::to_string::{
6    internal_generate_to_pretty_string_function_for_type, internal_generate_to_pretty_string_parameterless_function_for_type,
7    internal_generate_to_short_string_function_for_type,
8    internal_generate_to_string_function_for_type,
9    ExpressionGenerator,
10};
11use crate::types::TypeAnalyzeContext;
12use crate::Analyzer;
13use seq_map::SeqMap;
14use std::rc::Rc;
15use swamp_ast::Node;
16use swamp_attributes::Attributes;
17use swamp_modules::symtbl::AliasType;
18use swamp_semantic::err::ErrorKind;
19use swamp_semantic::{
20    ExternalFunctionDefinition, ExternalFunctionId, Function, InternalFunctionDefinition,
21    InternalFunctionId, LocalIdentifier, UseItem,
22};
23use swamp_symbol::{Symbol, SymbolKind, TopLevelSymbolId};
24use swamp_types::prelude::*;
25use tracing::debug;
26
27impl Analyzer<'_> {
28    fn general_import(
29        &mut self,
30        path: &[String],
31        import_items: &swamp_ast::ImportItems,
32        node: &swamp_ast::Node,
33    ) {
34        let found_module = if let Some(module) = self.shared.get_module(path) {
35            module.clone()
36        } else {
37            self.add_err(ErrorKind::UnknownModule, node);
38            return;
39        };
40
41        let name_node = self.to_node(node);
42
43        match import_items {
44            swamp_ast::ImportItems::Nothing => {
45                let last_name = path.last().unwrap();
46                if self
47                    .shared
48                    .lookup_table
49                    .get_module_link(last_name)
50                    .is_none()
51                {
52                    match self
53                        .shared
54                        .lookup_table
55                        .add_module_link(last_name, &name_node, found_module.clone())
56                    {
57                        Ok(_x) => {}
58                        Err(err) => {
59                            self.add_err(ErrorKind::SemanticError(err), node);
60                        }
61                    }
62                }
63            }
64            swamp_ast::ImportItems::Items(items) => {
65                for ast_items in items {
66                    match ast_items {
67                        swamp_ast::ImportItem::Identifier(node) => {
68                            let ident_resolved_node = self.to_node(&node.0);
69                            let ident = UseItem::Identifier(ident_resolved_node.clone());
70                            let ident_text =
71                                self.get_text_resolved(&ident_resolved_node).to_string();
72                            if let Some(found_symbol) =
73                                found_module.definition_table.get_symbol(&ident_text)
74                            {
75                                if let Err(sem_err) = self
76                                    .shared
77                                    .lookup_table
78                                    .add_symbol(&ident_text, found_symbol.clone())
79                                {
80                                    self.add_err(ErrorKind::SemanticError(sem_err), &node.0);
81                                    return;
82                                }
83                            } else {
84                                return self.add_err_resolved(
85                                    ErrorKind::UnknownTypeReference,
86                                    &ident_resolved_node,
87                                );
88                            }
89                            ident
90                        }
91                        swamp_ast::ImportItem::Type(node) => {
92                            let ident_resolved_node = self.to_node(&node.0);
93                            let ident_text =
94                                self.get_text_resolved(&ident_resolved_node).to_string();
95                            if let Some(found_symbol) =
96                                found_module.definition_table.get_symbol(&ident_text)
97                            {
98                                if let Err(sem_err) = self
99                                    .shared
100                                    .lookup_table
101                                    .add_symbol(&ident_text, found_symbol.clone())
102                                {
103                                    self.add_err(ErrorKind::SemanticError(sem_err), &node.0);
104                                    return;
105                                }
106                            } else {
107                                return self.add_err_resolved(
108                                    ErrorKind::UnknownTypeReference,
109                                    &ident_resolved_node,
110                                );
111                            }
112                            UseItem::TypeIdentifier(self.to_node(&node.0))
113                        }
114                    };
115                }
116            }
117            swamp_ast::ImportItems::All => {
118                if let Err(sem_err) = self
119                    .shared
120                    .lookup_table
121                    .extend_from(&found_module.definition_table)
122                {
123                    self.add_err(ErrorKind::SemanticError(sem_err), node);
124                }
125            }
126        }
127    }
128
129    fn analyze_mod_definition(&mut self, mod_definition: &swamp_ast::Mod) {
130        let mut path = Vec::new();
131        for ast_node in &mod_definition.module_path.0 {
132            path.push(self.get_text(ast_node).to_string());
133        }
134
135        let mut nodes_copy = path.clone();
136        nodes_copy.insert(0, "crate".to_string());
137
138        self.general_import(
139            &nodes_copy,
140            &mod_definition.items,
141            &mod_definition.module_path.0[0],
142        );
143    }
144
145    fn analyze_use_definition(&mut self, use_definition: &swamp_ast::Use) {
146        let mut nodes = Vec::new();
147        for ast_node in &use_definition.module_path.0 {
148            nodes.push(self.to_node(ast_node));
149        }
150
151        let path: Vec<String> = nodes
152            .iter()
153            .map(|node| {
154                let text = self.get_text_resolved(node);
155                text.to_string()
156            })
157            .collect();
158
159        self.general_import(
160            &path,
161            &use_definition.items,
162            &use_definition.module_path.0[0],
163        );
164    }
165
166    fn analyze_enum_type_definition(
167        &mut self,
168        enum_type_name: &swamp_ast::LocalTypeIdentifierWithOptionalTypeVariables,
169        ast_variants: &[swamp_ast::EnumVariantType],
170    ) {
171        let mut resolved_variants = SeqMap::new();
172
173        let name_node = self.to_node(&enum_type_name.name);
174
175        let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
176        self.shared.state.symbols.insert_top(symbol_id, Symbol {
177            id: symbol_id.into(),
178            kind: SymbolKind::Enum,
179            source_map_node: name_node.clone(),
180            name: name_node.clone(),
181        });
182
183        let mut new_enum_type = EnumType {
184            symbol_id,
185            name: name_node,
186            assigned_name: self.get_text(&enum_type_name.name).to_string(),
187            module_path: vec![],
188            variants: SeqMap::default(),
189            instantiated_type_parameters: Vec::default(),
190        };
191
192        for (container_index_usize, ast_variant_type) in ast_variants.iter().enumerate() {
193            let variant_name_node = match ast_variant_type {
194                swamp_ast::EnumVariantType::Simple(name) => name,
195                swamp_ast::EnumVariantType::Direct(name, _) => name,
196                swamp_ast::EnumVariantType::Tuple(name, _) => name,
197                swamp_ast::EnumVariantType::Struct(name, _) => name,
198            };
199
200            let name_node_for_variant = self.to_node(variant_name_node);
201
202            let variant_symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
203            self.shared.state.symbols.insert_top(variant_symbol_id, Symbol {
204                id: variant_symbol_id.into(),
205                kind: SymbolKind::EnumVariant,
206                source_map_node: name_node_for_variant.clone(),
207                name: name_node_for_variant.clone(),
208            });
209
210            let common = EnumVariantCommon {
211                symbol_id: variant_symbol_id,
212                name: name_node_for_variant,
213                assigned_name: self.get_text(variant_name_node).to_string(),
214                container_index: container_index_usize as u8,
215            };
216
217            let payload_type = match ast_variant_type {
218                swamp_ast::EnumVariantType::Simple(_variant_name_node) => self.types().unit(),
219                swamp_ast::EnumVariantType::Direct(_variant_name_node, direct_type) => {
220                    let analyzed_type =
221                        self.analyze_type(direct_type, &TypeAnalyzeContext::default());
222                    // If the direct_type is actually a single-element tuple, unwrap it
223                    match &*analyzed_type.kind {
224                        TypeKind::Tuple(elements) if elements.len() == 1 => elements[0].clone(),
225                        _ => analyzed_type,
226                    }
227                }
228                swamp_ast::EnumVariantType::Tuple(_variant_name_node, types) => {
229                    let mut vec = Vec::new();
230                    for tuple_type in types {
231                        let resolved_type =
232                            self.analyze_type(tuple_type, &TypeAnalyzeContext::default());
233                        vec.push(resolved_type);
234                    }
235
236                    // Single-element tuples should be treated as direct types
237                    if vec.len() == 1 {
238                        vec.into_iter().next().unwrap()
239                    } else {
240                        self.types().tuple(vec)
241                    }
242                }
243                swamp_ast::EnumVariantType::Struct(_variant_name_node, ast_struct_fields) => {
244                    let mut fields = SeqMap::new();
245
246                    for field_with_type in &ast_struct_fields.fields {
247                        let resolved_type = self.analyze_type(
248                            &field_with_type.field_type,
249                            &TypeAnalyzeContext::default(),
250                        );
251                        let field_name_str =
252                            self.get_text(&field_with_type.field_name.0).to_string();
253
254                        let name_node = self.to_node(&field_with_type.field_name.0);
255
256                        let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
257                        self.shared.state.symbols.insert_top(symbol_id, Symbol {
258                            id: symbol_id.into(),
259                            kind: SymbolKind::EnumPayloadStructField,
260                            source_map_node: name_node.clone(),
261                            name: name_node.clone(),
262                        });
263
264                        let resolved_field = StructTypeField {
265                            symbol_id,
266                            identifier: Some(name_node),
267                            field_type: resolved_type,
268                        };
269
270                        if let Err(_seq_map_err) = fields.insert(field_name_str, resolved_field) {
271                            return self.add_err(
272                                ErrorKind::DuplicateFieldName,
273                                &field_with_type.field_name.0,
274                            );
275                        }
276                    }
277
278                    let anonymous_struct_type = AnonymousStructType {
279                        field_name_sorted_fields: fields,
280                    };
281
282                    self.types().anonymous_struct(anonymous_struct_type)
283                }
284            };
285
286            let enum_variant_type = swamp_types::prelude::EnumVariantType {
287                common,
288                payload_type,
289            };
290
291            let variant_name_str = self.get_text(variant_name_node).to_string();
292
293            if let Err(_seq_map_err) = resolved_variants.insert(variant_name_str, enum_variant_type)
294            {
295                return self.add_err(ErrorKind::DuplicateFieldName, variant_name_node);
296            }
297        }
298
299        new_enum_type.variants = resolved_variants;
300
301        let enum_type_ref = self.shared.state.types.enum_type(new_enum_type);
302
303        if let Err(sem_err) = self
304            .shared
305            .definition_table
306            .add_named_type(enum_type_ref.clone())
307        {
308            return self.add_err(ErrorKind::SemanticError(sem_err), &enum_type_name.name);
309        }
310
311        if let Err(sem_err) = self
312            .shared
313            .lookup_table
314            .add_named_type(enum_type_ref.clone())
315        {
316            return self.add_err(ErrorKind::SemanticError(sem_err), &enum_type_name.name);
317        }
318
319        self.add_default_functions(&enum_type_ref, &enum_type_name.name);
320    }
321
322    /// # Errors
323    ///
324    pub fn analyze_alias_type_definition(&mut self, ast_alias: &swamp_ast::AliasType) -> AliasType {
325        let resolved_type =
326            self.analyze_type(&ast_alias.referenced_type, &TypeAnalyzeContext::default());
327
328        // Ensure string functions are generated for the resolved type
329        self.ensure_default_functions_for_type(&resolved_type, &ast_alias.identifier.0);
330
331        let alias_name_str = self.get_text(&ast_alias.identifier.0).to_string();
332        let name_node = self.to_node(&ast_alias.identifier.0);
333        let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
334        self.shared.state.symbols.insert_top(symbol_id, Symbol {
335            id: symbol_id.into(),
336            kind: SymbolKind::Alias,
337            source_map_node: name_node.clone(),
338            name: name_node.clone(),
339        });
340        let resolved_alias = AliasType {
341            symbol_id,
342            name: name_node,
343            ty: resolved_type,
344            assigned_name: alias_name_str,
345        };
346
347        let resolved_alias_ref = match self.shared.definition_table.add_alias(resolved_alias) {
348            Ok(re) => re,
349
350            Err(err) => {
351                self.add_err(ErrorKind::SemanticError(err), &ast_alias.identifier.0);
352                AliasType {
353                    symbol_id: TopLevelSymbolId::new_illegal(),
354                    name: source_map_node::Node::default(),
355                    assigned_name: "err".to_string(),
356                    ty: self.types().unit(),
357                }
358            }
359        };
360
361        if let Err(sem_err) = self
362            .shared
363            .lookup_table
364            .add_alias_link(resolved_alias_ref.clone())
365        {
366            self.add_err(ErrorKind::SemanticError(sem_err), &ast_alias.identifier.0);
367            AliasType {
368                symbol_id: TopLevelSymbolId::new_illegal(),
369                name: source_map_node::Node::default(),
370                assigned_name: "err".to_string(),
371                ty: self.types().unit(),
372            }
373        } else {
374            resolved_alias_ref
375        }
376    }
377
378    /// # Errors
379    ///
380    pub fn analyze_anonymous_struct_type(
381        &mut self,
382        ast_struct: &swamp_ast::AnonymousStructType,
383        ctx: &TypeAnalyzeContext,
384    ) -> AnonymousStructType {
385        let resolved_fields = self.analyze_anonymous_struct_type_fields(&ast_struct.fields, ctx);
386
387        AnonymousStructType::new_and_sort_fields(&resolved_fields)
388    }
389
390    /// # Errors
391    ///
392    pub fn analyze_anonymous_struct_type_fields(
393        &mut self,
394        ast_struct_fields: &[swamp_ast::StructTypeField],
395        ctx: &TypeAnalyzeContext,
396    ) -> SeqMap<String, StructTypeField> {
397        let mut resolved_fields = SeqMap::new();
398
399        for field_name_and_type in ast_struct_fields {
400            let resolved_type = self.analyze_type(&field_name_and_type.field_type, ctx);
401            let name_string = self.get_text(&field_name_and_type.field_name.0).to_string();
402
403            if !resolved_type.can_be_stored_in_transient_field() {
404                self.add_err(ErrorKind::NeedStorage, &field_name_and_type.field_name.0);
405                return resolved_fields;
406            }
407
408            if !resolved_type.can_be_stored_in_field() {
409                self.add_hint(ErrorKind::NeedStorage, &field_name_and_type.field_name.0);
410            }
411            let name_node = self.to_node(&field_name_and_type.field_name.0);
412
413            let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
414            self.shared.state.symbols.insert_top(symbol_id, Symbol {
415                id: symbol_id.into(),
416                kind: SymbolKind::NamedStructField,
417                source_map_node: name_node.clone(),
418                name: name_node.clone(),
419            });
420
421            let field_type = StructTypeField {
422                symbol_id,
423                identifier: Some(name_node),
424                field_type: resolved_type,
425            };
426
427            if let Err(_seq_map_err) = resolved_fields.insert(name_string, field_type) {
428                self.add_err(
429                    ErrorKind::DuplicateFieldName,
430                    &field_name_and_type.field_name.0,
431                );
432            }
433        }
434
435        resolved_fields
436    }
437
438    /// # Errors
439    ///
440    pub fn analyze_named_struct_type_definition(
441        &mut self,
442        ast_struct_def: &swamp_ast::NamedStructDef,
443    ) {
444        let struct_name_str = self.get_text(&ast_struct_def.identifier.name).to_string();
445
446        let fields = self.analyze_anonymous_struct_type_fields(
447            &ast_struct_def.struct_type.fields,
448            &TypeAnalyzeContext::default(),
449        );
450
451        let analyzed_anonymous_struct = AnonymousStructType::new(fields);
452
453        let anon_struct_type_ref = self
454            .shared
455            .state
456            .types
457            .anonymous_struct(analyzed_anonymous_struct);
458
459        let name_node = self.to_node(&ast_struct_def.identifier.name);
460
461        let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
462        self.shared.state.symbols.insert_top(symbol_id, Symbol {
463            id: symbol_id.into(),
464            kind: SymbolKind::NamedStruct,
465            source_map_node: name_node.clone(),
466            name: name_node.clone(),
467        });
468
469
470        let named_struct_type = NamedStructType {
471            symbol_id,
472            name: name_node,
473            anon_struct_type: anon_struct_type_ref,
474            assigned_name: struct_name_str,
475            module_path: self.shared.definition_table.module_path(),
476        };
477
478        let named_struct_type_ref = self.shared.state.types.named_struct(named_struct_type);
479
480        match self
481            .shared
482            .definition_table
483            .add_named_type(named_struct_type_ref.clone())
484        {
485            Ok(()) => {}
486            Err(sem_err) => {
487                return self.add_err(
488                    ErrorKind::SemanticError(sem_err),
489                    &ast_struct_def.identifier.name,
490                );
491            }
492        }
493
494        match self
495            .shared
496            .lookup_table
497            .add_named_type(named_struct_type_ref.clone())
498        {
499            Ok(()) => {}
500            Err(sem_err) => {
501                return self.add_err(
502                    ErrorKind::SemanticError(sem_err),
503                    &ast_struct_def.identifier.name,
504                );
505            }
506        }
507
508        self.add_default_functions(&named_struct_type_ref, &ast_struct_def.identifier.name);
509    }
510
511    #[allow(clippy::too_many_lines)]
512    pub(crate) fn analyze_function_definition(
513        &mut self,
514        function: &swamp_ast::Function,
515        attributes: &Attributes,
516    ) -> Option<Function> {
517        let func = match &function {
518            swamp_ast::Function::Internal(function_data) => {
519                let parameters = self.analyze_parameters(&function_data.declaration.params);
520                let return_type = if let Some(found) = &function_data.declaration.return_type {
521                    let analyzed_return_type =
522                        self.analyze_type(found, &TypeAnalyzeContext::default());
523                    if !analyzed_return_type.allowed_as_return_type() {
524                        self.add_err(
525                            ErrorKind::NotAllowedAsReturnType(analyzed_return_type),
526                            function.node(),
527                        );
528                        return None;
529                    }
530                    analyzed_return_type
531                } else {
532                    self.shared.state.types.unit()
533                };
534
535                for param in &parameters {
536                    let param_type = &param.resolved_type;
537                    let actual_type = param_type.clone();
538                    self.create_parameter_resolved(
539                        &param.node.as_ref().unwrap().name,
540                        param.node.as_ref().unwrap().is_mutable.as_ref(),
541                        &actual_type,
542                    );
543                }
544                let function_name = self
545                    .get_text(&function_data.declaration.name)
546                    .trim()
547                    .to_string();
548
549                let name_node = self.to_node(&function_data.declaration.name);
550                let statements =
551                    self.analyze_function_body_expression(&function_data.body, &return_type);
552
553                let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
554                self.shared.state.symbols.insert_top(symbol_id, Symbol {
555                    id: symbol_id.into(),
556                    kind: SymbolKind::Function,
557                    source_map_node: name_node.clone(),
558                    name: name_node.clone(),
559                });
560                let internal = InternalFunctionDefinition {
561                    symbol_id,
562                    signature: Signature {
563                        parameters,
564                        return_type,
565                    },
566                    body: statements,
567                    name: LocalIdentifier(name_node),
568                    assigned_name: self.get_text(&function_data.declaration.name).to_string(),
569                    associated_with_type: None,
570                    defined_in_module_path: self.module_path.clone(),
571                    function_variables: self.scope.total_scopes.clone(),
572                    program_unique_id: self.shared.state.allocate_internal_function_id(),
573                    attributes: attributes.clone(),
574                };
575
576                let function_ref = match self
577                    .shared
578                    .definition_table
579                    .add_internal_function(&function_name, internal)
580                {
581                    Ok(func_def) => func_def,
582                    Err(sem_err) => {
583                        self.add_err(
584                            ErrorKind::SemanticError(sem_err),
585                            &function_data.declaration.name,
586                        );
587                        return None;
588                    }
589                };
590
591                match self
592                    .shared
593                    .lookup_table
594                    .add_internal_function_link(&function_name, function_ref.clone())
595                {
596                    Ok(()) => {}
597                    Err(sem_err) => {
598                        self.add_err(
599                            ErrorKind::SemanticError(sem_err),
600                            &function_data.declaration.name,
601                        );
602                        return None;
603                    }
604                }
605
606                Function::Internal(function_ref)
607            }
608            swamp_ast::Function::External(int_node, ast_signature) => {
609                let parameters = self.analyze_parameters(&ast_signature.params);
610                let external_return_type = if let Some(found) = &ast_signature.return_type {
611                    self.analyze_type(found, &TypeAnalyzeContext::default())
612                } else {
613                    self.shared.state.types.unit()
614                };
615
616                let return_type = external_return_type;
617
618                let int_string = self.get_text(int_node);
619                let external_function_id_int = Self::str_to_int(int_string).unwrap() as u32;
620
621                let external_function_id = external_function_id_int as ExternalFunctionId;
622
623                let external = ExternalFunctionDefinition {
624                    assigned_name: self.get_text(&ast_signature.name).to_string(),
625                    signature: Signature {
626                        parameters,
627                        return_type,
628                    },
629                    name: self.to_node(&ast_signature.name),
630                    id: external_function_id,
631                };
632
633                let function_ref = match self
634                    .shared
635                    .definition_table
636                    .add_external_function_declaration(external)
637                {
638                    Ok(func_ref) => func_ref,
639                    Err(sem_err) => {
640                        self.add_err(ErrorKind::SemanticError(sem_err), &ast_signature.name);
641                        return None;
642                    }
643                };
644
645                if let Err(sem_err) = self
646                    .shared
647                    .lookup_table
648                    .add_external_function_declaration_link(function_ref.clone())
649                {
650                    self.add_err(ErrorKind::SemanticError(sem_err), &ast_signature.name);
651                    return None;
652                }
653
654                Function::External(function_ref)
655            }
656        };
657
658        Some(func)
659    }
660
661    pub fn debug_definition(&self, definition: &swamp_ast::Definition) {
662        let (line, col) = self
663            .shared
664            .source_map
665            .get_span_location_utf8(self.shared.file_id, definition.node.span.offset as usize);
666        let source_line = self
667            .shared
668            .source_map
669            .get_source_line(self.shared.file_id, line)
670            .unwrap();
671        debug!(?line, ?col, ?source_line);
672    }
673
674    /// # Errors
675    ///
676    pub fn analyze_definition(&mut self, ast_def: &swamp_ast::Definition) {
677        //self.debug_definition(ast_def);
678
679        let analyzed_attributes = self.analyze_attributes(&ast_def.attributes);
680
681        match &ast_def.kind {
682            swamp_ast::DefinitionKind::NamedStructDef(ast_struct) => {
683                self.analyze_named_struct_type_definition(ast_struct);
684            }
685            swamp_ast::DefinitionKind::AliasDef(alias_def) => {
686                self.analyze_alias_type_definition(alias_def);
687            }
688            swamp_ast::DefinitionKind::EnumDef(identifier, variants) => {
689                self.analyze_enum_type_definition(identifier, variants);
690            }
691            swamp_ast::DefinitionKind::FunctionDef(function) => {
692                let _resolved_return_type = self.analyze_return_type(function);
693                self.start_function(function.node());
694                self.analyze_function_definition(function, &analyzed_attributes);
695                self.stop_function();
696            }
697            swamp_ast::DefinitionKind::ImplDef(type_identifier, functions) => {
698                self.analyze_impl_definition(type_identifier, functions);
699            }
700            swamp_ast::DefinitionKind::Mod(mod_info) => self.analyze_mod_definition(mod_info),
701            swamp_ast::DefinitionKind::Use(use_info) => self.analyze_use_definition(use_info),
702            swamp_ast::DefinitionKind::Constant(const_info) => {
703                self.analyze_constant_definition(const_info);
704            }
705        }
706    }
707
708    fn analyze_impl_definition(
709        &mut self,
710        attached_to_type: &swamp_ast::LocalTypeIdentifierWithOptionalTypeVariables,
711        functions: &[swamp_ast::Function],
712    ) {
713        let converted_type_variables_to_ast_types = attached_to_type
714            .type_variables
715            .iter()
716            .map(|x| {
717                swamp_ast::GenericParameter::Type(swamp_ast::Type::Named(
718                    swamp_ast::QualifiedTypeIdentifier {
719                        name: swamp_ast::LocalTypeIdentifier(x.0.clone()),
720                        module_path: None,
721                        generic_params: vec![],
722                    },
723                ))
724            })
725            .collect();
726
727        let qualified = swamp_ast::QualifiedTypeIdentifier {
728            name: swamp_ast::LocalTypeIdentifier(attached_to_type.name.clone()),
729            module_path: None,
730            generic_params: converted_type_variables_to_ast_types,
731        };
732
733        let maybe_type_to_attach_to = Some(self.analyze_named_type(&qualified));
734        if let Some(type_to_attach_to) = maybe_type_to_attach_to {
735            let function_refs: Vec<&swamp_ast::Function> = functions.iter().collect();
736            self.analyze_impl_functions(&type_to_attach_to, &function_refs);
737        } else {
738            self.add_err(
739                ErrorKind::CanNotAttachFunctionsToType,
740                &attached_to_type.name,
741            );
742        }
743    }
744
745    /// # Errors
746    ///
747    pub fn analyze_impl_functions(
748        &mut self,
749        attach_to_type: &TypeRef,
750        functions: &[&swamp_ast::Function],
751    ) {
752        if !self
753            .shared
754            .state
755            .associated_impls
756            .is_prepared(attach_to_type)
757        {
758            self.shared.state.associated_impls.prepare(attach_to_type);
759        }
760
761        for function in functions {
762
763            let function_name = match function {
764                swamp_ast::Function::Internal(function_with_body) => {
765                    &function_with_body.declaration
766                }
767                swamp_ast::Function::External(_, external_declaration) => external_declaration,
768            };
769            self.start_function(&function_name.name);
770
771            let function_name_str = self.get_text(&function_name.name).to_string();
772
773            let existing_function_id = if matches!(
774                function_name_str.as_str(),
775                "string"
776                    | "short_string"
777                    | "pretty_string"
778                    | "pretty_string_with_indent"
779                    | "default"
780            ) {
781                self.shared
782                    .state
783                    .associated_impls
784                    .get_internal_member_function(attach_to_type, &function_name_str)
785                    .map(|existing_fn| existing_fn.program_unique_id)
786            } else {
787                None
788            };
789
790            let resolved_function =
791                self.analyze_impl_func(function, attach_to_type, existing_function_id);
792
793            let resolved_function_ref = Rc::new(resolved_function);
794
795            self.stop_function();
796
797            let is_built_in = matches!(
798                function_name_str.as_str(),
799                "string"
800                    | "short_string"
801                    | "pretty_string"
802                    | "pretty_string_with_indent"
803                    | "default"
804            );
805            if is_built_in {
806                self.shared
807                    .state
808                    .associated_impls
809                    .remove_internal_function_if_exists(attach_to_type, &function_name_str);
810            }
811
812            if let Err(sem_err) = self.shared.state.associated_impls.add_member_function(
813                attach_to_type,
814                &function_name_str,
815                resolved_function_ref,
816            ) {
817                return self.add_err(ErrorKind::SemanticError(sem_err), &function_name.name);
818            }
819        }
820    }
821
822    #[allow(clippy::too_many_lines)]
823    fn analyze_impl_func(
824        &mut self,
825        function: &swamp_ast::Function,
826        self_type: &TypeRef,
827        existing_function_id: Option<InternalFunctionId>,
828    ) -> Function {
829        match function {
830            swamp_ast::Function::Internal(function_data) => {
831                let mut parameters = Vec::new();
832
833                if let Some(found_self) = &function_data.declaration.self_parameter {
834                    let actual_self_type = self_type.clone();
835                    parameters.push(TypeForParameter {
836                        name: self.get_text(&found_self.self_node).to_string(),
837                        resolved_type: actual_self_type,
838                        is_mutable: found_self.is_mutable.is_some(),
839                        node: Option::from(ParameterNode {
840                            name: self.to_node(&found_self.self_node),
841                            is_mutable: self.to_node_option(Option::from(&found_self.is_mutable)),
842                        }),
843                    });
844                }
845
846                for param in &function_data.declaration.params {
847                    let resolved_type =
848                        self.analyze_type(&param.param_type, &TypeAnalyzeContext::default());
849
850                    let resolved_param = TypeForParameter {
851                        name: self.get_text(&param.variable.name).to_string(),
852                        resolved_type,
853                        is_mutable: param.variable.is_mutable.is_some(),
854                        node: Option::from(ParameterNode {
855                            name: self.to_node(&param.variable.name),
856                            is_mutable: self
857                                .to_node_option(Option::from(&param.variable.is_mutable)),
858                        }),
859                    };
860
861                    parameters.push(resolved_param);
862                }
863
864                let return_type =
865                    if let Some(ast_return_type) = &function_data.declaration.return_type {
866                        self.analyze_type(ast_return_type, &TypeAnalyzeContext::default())
867                    } else {
868                        self.shared.state.types.unit()
869                    };
870
871                for param in &parameters {
872                    self.create_parameter_resolved(
873                        &param.node.as_ref().unwrap().name,
874                        param.node.as_ref().unwrap().is_mutable.as_ref(),
875                        &param.resolved_type.clone(),
876                    );
877                }
878
879                let statements =
880                    self.analyze_function_body_expression(&function_data.body, &return_type);
881
882                let attributes = self.analyze_attributes(&function_data.attributes);
883
884                let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
885
886                let name_node = self.to_node(&function_data.declaration.name);
887                self.shared.state.symbols.insert_top(symbol_id, Symbol {
888                    id: symbol_id.into(),
889                    kind: SymbolKind::MemberFunction,
890                    source_map_node: name_node.clone(),
891                    name: name_node.clone(),
892                });
893
894                let internal = InternalFunctionDefinition {
895                    symbol_id,
896                    signature: Signature {
897                        parameters,
898                        return_type,
899                    },
900                    body: statements,
901                    name: LocalIdentifier(name_node),
902                    assigned_name: self.get_text(&function_data.declaration.name).to_string(),
903                    defined_in_module_path: self.module_path.clone(),
904                    associated_with_type: Some(self_type.clone()),
905                    function_variables: self.scope.total_scopes.clone(),
906                    program_unique_id: existing_function_id
907                        .unwrap_or_else(|| self.shared.state.allocate_internal_function_id()),
908                    attributes,
909                };
910
911                let internal_ref = Rc::new(internal);
912
913                Function::Internal(internal_ref)
914            }
915
916            swamp_ast::Function::External(int_node, signature) => {
917                let mut parameters = Vec::new();
918
919                if let Some(found_self) = &signature.self_parameter {
920                    let param = TypeForParameter {
921                        name: self.get_text(&found_self.self_node).to_string(),
922                        resolved_type: self_type.clone(),
923                        is_mutable: found_self.is_mutable.is_some(),
924                        node: Option::from(ParameterNode {
925                            name: self.to_node(&found_self.self_node),
926                            is_mutable: self.to_node_option(Option::from(&found_self.is_mutable)),
927                        }),
928                    };
929
930                    parameters.push(param);
931                }
932
933                for param in &signature.params {
934                    let resolved_type =
935                        self.analyze_type(&param.param_type, &TypeAnalyzeContext::default());
936
937                    parameters.push(TypeForParameter {
938                        name: self.get_text(&param.variable.name).to_string(),
939                        resolved_type,
940                        is_mutable: param.variable.is_mutable.is_some(),
941                        node: Option::from(ParameterNode {
942                            name: self.to_node(&param.variable.name),
943                            is_mutable: self
944                                .to_node_option(Option::from(&param.variable.is_mutable)),
945                        }),
946                    });
947                }
948
949                let return_type = self.analyze_maybe_type(Option::from(&signature.return_type));
950
951                let int_string = self.get_text(int_node);
952                let external_function_id_int = Self::str_to_int(int_string).unwrap() as u32;
953
954                let external_function_id = external_function_id_int as ExternalFunctionId;
955
956                let external = ExternalFunctionDefinition {
957                    assigned_name: self.get_text(&signature.name).to_string(),
958                    name: self.to_node(&signature.name),
959                    signature: Signature {
960                        parameters,
961                        return_type,
962                    },
963                    id: external_function_id,
964                };
965
966                let external_ref = Rc::new(external);
967
968                Function::External(external_ref)
969            }
970        }
971    }
972
973    /// Called whenever a type is resolved/created during analysis to ensure string functions exist
974    pub fn on_type_encountered(&mut self, ty: &TypeRef, node: &swamp_ast::Node) {
975        // Only generate string functions for types that need them and don't already have them
976        if self.needs_any_string_functions(ty) {
977            // Check if we already have the functions to avoid infinite recursion
978            if !self.shared.state.associated_impls.is_prepared(ty)
979                || self
980                .shared
981                .state
982                .associated_impls
983                .get_internal_member_function(ty, "string")
984                .is_none()
985            {
986                self.add_default_functions(ty, node);
987            }
988        }
989    }
990
991    // Helper method to check if a type needs any string functions
992    fn needs_any_string_functions(&self, ty: &TypeRef) -> bool {
993        // Types that should not have generated string functions:
994        // - Primitives: handled in core_text()
995        // - String types: (they return themselves)
996        // - Function types: (cannot be stored in fields)
997        let should_not_have_string_functions = matches!(
998            &*ty.kind,
999            TypeKind::Any
1000                | TypeKind::Byte
1001                | TypeKind::Codepoint
1002                | TypeKind::Int
1003                | TypeKind::Float
1004                | TypeKind::Bool
1005                | TypeKind::Range(_)
1006                | TypeKind::String(..)
1007                | TypeKind::Function(_)
1008        );
1009
1010        if should_not_have_string_functions {
1011            return false;
1012        }
1013
1014        // Early check - if not prepared at all, definitely needs functions
1015        if !self.shared.state.associated_impls.is_prepared(ty) {
1016            return true;
1017        }
1018
1019        let has_to_string = self
1020            .shared
1021            .state
1022            .associated_impls
1023            .get_internal_member_function(ty, "string")
1024            .is_some();
1025
1026        let has_to_short_string = self
1027            .shared
1028            .state
1029            .associated_impls
1030            .get_internal_member_function(ty, "short_string")
1031            .is_some();
1032
1033        let has_to_pretty_string = self
1034            .shared
1035            .state
1036            .associated_impls
1037            .get_internal_member_function(ty, "pretty_string")
1038            .is_some();
1039
1040        let has_to_pretty_string_with_indent = self
1041            .shared
1042            .state
1043            .associated_impls
1044            .get_internal_member_function(ty, "pretty_string_with_indent")
1045            .is_some();
1046
1047        !has_to_string
1048            || !has_to_short_string
1049            || !has_to_pretty_string
1050            || !has_to_pretty_string_with_indent
1051    }
1052
1053    pub fn add_default_functions(&mut self, type_to_attach_to: &TypeRef, node: &swamp_ast::Node) {
1054        if let TypeKind::Enum(enum_type) = &*type_to_attach_to.kind {
1055            for (_, variant) in &enum_type.variants {
1056                if !matches!(&*variant.payload_type.kind, TypeKind::Unit)
1057                    && !TypeRef::ptr_eq(&variant.payload_type, type_to_attach_to)
1058                {
1059                    let needs_string_functions =
1060                        self.needs_any_string_functions(&variant.payload_type);
1061
1062                    if needs_string_functions {
1063                        self.add_default_functions(&variant.payload_type, node);
1064                    }
1065                }
1066            }
1067        }
1068
1069        // Also check tuple elements and other nested types
1070        match &*type_to_attach_to.kind {
1071            TypeKind::Tuple(tuple_types) => {
1072                for element_type in tuple_types {
1073                    if self.needs_any_string_functions(element_type) {
1074                        self.add_default_functions(element_type, node);
1075                    }
1076                }
1077            }
1078            TypeKind::Optional(inner_type) => {
1079                if self.needs_any_string_functions(inner_type) {
1080                    self.add_default_functions(inner_type, node);
1081                }
1082            }
1083            TypeKind::FixedCapacityAndLengthArray(element_type, _)
1084            | TypeKind::SliceView(element_type)
1085            | TypeKind::DynamicLengthVecView(element_type)
1086            | TypeKind::VecStorage(element_type, _)
1087            | TypeKind::StackView(element_type)
1088            | TypeKind::QueueView(element_type)
1089            | TypeKind::StackStorage(element_type, _)
1090            | TypeKind::QueueStorage(element_type, _)
1091            | TypeKind::SparseView(element_type)
1092            | TypeKind::SparseStorage(element_type, _)
1093            | TypeKind::GridView(element_type)
1094            | TypeKind::GridStorage(element_type, _, _) => {
1095                if self.needs_any_string_functions(element_type) {
1096                    self.add_default_functions(element_type, node);
1097                }
1098            }
1099            TypeKind::MapStorage(key_type, value_type, _)
1100            | TypeKind::DynamicLengthMapView(key_type, value_type) => {
1101                if self.needs_any_string_functions(key_type) {
1102                    self.add_default_functions(key_type, node);
1103                }
1104                if self.needs_any_string_functions(value_type) {
1105                    self.add_default_functions(value_type, node);
1106                }
1107            }
1108            _ => {}
1109        }
1110
1111        let underlying = type_to_attach_to;
1112
1113        if self.needs_any_string_functions(underlying) {
1114            if !self
1115                .shared
1116                .state
1117                .associated_impls
1118                .is_prepared(type_to_attach_to)
1119            {
1120                self.shared
1121                    .state
1122                    .associated_impls
1123                    .prepare(type_to_attach_to);
1124            }
1125
1126            if self
1127                .shared
1128                .state
1129                .associated_impls
1130                .get_internal_member_function(underlying, "string")
1131                .is_none()
1132            {
1133                let to_string_function =
1134                    self.generate_to_string_function_for_type(type_to_attach_to, node);
1135                self.shared
1136                    .state
1137                    .associated_impls
1138                    .add_internal_function(type_to_attach_to, to_string_function)
1139                    .unwrap();
1140            }
1141
1142            if self
1143                .shared
1144                .state
1145                .associated_impls
1146                .get_internal_member_function(underlying, "short_string")
1147                .is_none()
1148            {
1149                let to_short_string_function =
1150                    self.generate_to_short_string_function_for_type(type_to_attach_to, node);
1151                self.shared
1152                    .state
1153                    .associated_impls
1154                    .add_internal_function(type_to_attach_to, to_short_string_function)
1155                    .unwrap();
1156            }
1157
1158            if self
1159                .shared
1160                .state
1161                .associated_impls
1162                .get_internal_member_function(underlying, "pretty_string")
1163                .is_none()
1164            {
1165                let to_pretty_string_function = self
1166                    .generate_to_pretty_string_parameterless_function_for_type(
1167                        type_to_attach_to,
1168                        node,
1169                    );
1170                self.shared
1171                    .state
1172                    .associated_impls
1173                    .add_internal_function(type_to_attach_to, to_pretty_string_function)
1174                    .unwrap();
1175            }
1176
1177            if self
1178                .shared
1179                .state
1180                .associated_impls
1181                .get_internal_member_function(underlying, "pretty_string_with_indent")
1182                .is_none()
1183            {
1184                let to_pretty_string_with_indent_function =
1185                    self.generate_to_pretty_string_function_for_type(type_to_attach_to, node);
1186                self.shared
1187                    .state
1188                    .associated_impls
1189                    .add_internal_function(type_to_attach_to, to_pretty_string_with_indent_function)
1190                    .unwrap();
1191            }
1192        }
1193    }
1194
1195    /// Ensures that a type has all necessary string functions generated
1196    /// This should be called whenever a type is encountered during analysis
1197    pub fn ensure_default_functions_for_type(&mut self, ty: &TypeRef, node: &swamp_ast::Node) {
1198        if self.needs_any_string_functions(ty) {
1199            self.add_default_functions(ty, node);
1200        }
1201    }
1202
1203    fn generate_to_string_function_for_type(
1204        &mut self,
1205        ty: &TypeRef,
1206        ast_node: &Node,
1207    ) -> InternalFunctionDefinition {
1208        let node = self.to_node(ast_node);
1209        let mut generator = ExpressionGenerator::new(
1210            &mut self.shared.state.types,
1211            &self.shared.state.associated_impls,
1212        );
1213        internal_generate_to_string_function_for_type(
1214            &mut generator,
1215            &mut self.shared.state.internal_function_id_allocator,
1216            &mut self.shared.state.symbol_id_allocator,
1217            &mut self.shared.state.symbols,
1218            &self.module_path,
1219            ty,
1220            &node,
1221            false,
1222        )
1223    }
1224
1225    fn generate_to_short_string_function_for_type(
1226        &mut self,
1227        ty: &TypeRef,
1228        ast_node: &Node,
1229    ) -> InternalFunctionDefinition {
1230        let node = self.to_node(ast_node);
1231        let mut generator = ExpressionGenerator::new(
1232            &mut self.shared.state.types,
1233            &self.shared.state.associated_impls,
1234        );
1235        internal_generate_to_short_string_function_for_type(
1236            &mut generator,
1237            &mut self.shared.state.internal_function_id_allocator,
1238            &mut self.shared.state.symbol_id_allocator,
1239            &mut self.shared.state.symbols,
1240            &self.module_path,
1241            ty,
1242            &node,
1243        )
1244    }
1245
1246    fn generate_to_pretty_string_function_for_type(
1247        &mut self,
1248        ty: &TypeRef,
1249        ast_node: &Node,
1250    ) -> InternalFunctionDefinition {
1251        let node = self.to_node(ast_node);
1252        let mut generator = ExpressionGenerator::new(
1253            &mut self.shared.state.types,
1254            &self.shared.state.associated_impls,
1255        );
1256        internal_generate_to_pretty_string_function_for_type(
1257            &mut generator,
1258            &mut self.shared.state.internal_function_id_allocator,
1259            &mut self.shared.state.symbol_id_allocator,
1260            &mut self.shared.state.symbols,
1261            &self.module_path,
1262            ty,
1263            &node,
1264        )
1265    }
1266
1267    fn generate_to_pretty_string_parameterless_function_for_type(
1268        &mut self,
1269        ty: &TypeRef,
1270        ast_node: &Node,
1271    ) -> InternalFunctionDefinition {
1272        let node = self.to_node(ast_node);
1273        let mut generator = ExpressionGenerator::new(
1274            &mut self.shared.state.types,
1275            &self.shared.state.associated_impls,
1276        );
1277        internal_generate_to_pretty_string_parameterless_function_for_type(
1278            &mut generator,
1279            &mut self.shared.state.internal_function_id_allocator,
1280            &mut self.shared.state.symbol_id_allocator,
1281            &mut self.shared.state.symbols,
1282            &self.module_path,
1283            ty,
1284            &node,
1285        )
1286    }
1287}