swamp_analyzer/
lib.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 */
5pub mod access;
6mod attributes;
7pub mod call;
8pub mod constant;
9pub mod def;
10pub mod literal;
11pub mod operator;
12pub mod pattern;
13pub mod prelude;
14mod structure;
15mod to_string;
16pub mod types;
17pub mod variable;
18
19use crate::call::MaybeBorrowMutRefExpression;
20use crate::to_string::create_expr_resolved;
21use seq_map::SeqMap;
22use source_map_cache::SourceMap;
23use source_map_node::{FileId, Node, Span};
24use std::mem::take;
25use std::num::{ParseFloatError, ParseIntError};
26use std::rc::Rc;
27use std::str::{FromStr, ParseBoolError};
28use swamp_ast::{GenericParameter, QualifiedTypeIdentifier};
29use swamp_modules::prelude::*;
30use swamp_modules::symtbl::SymbolTableRef;
31use swamp_semantic::prelude::*;
32use swamp_semantic::{
33    ArgumentExpression, BinaryOperatorKind, BlockScope, BlockScopeMode, FunctionScopeState,
34    GridType, InternalMainExpression, LocationAccess, LocationAccessKind, MapType,
35    MutableReferenceKind, NormalPattern, Postfix, PostfixKind, ScopeInfo, SingleLocationExpression,
36    SliceViewType, SparseType, TargetAssignmentLocation, TypeWithMut, VariableType, VecType,
37    WhenBinding,
38};
39use swamp_semantic::{StartOfChain, StartOfChainKind};
40use swamp_types::prelude::*;
41use swamp_types::TypeKind;
42use tracing::error;
43
44#[derive(Copy, Clone, Eq, PartialEq)]
45pub enum AssignmentMode {
46    OwnedValue,
47    CopyBlittable,
48    CopySharedPtr,
49}
50
51#[derive(Copy, Clone, Eq, PartialEq, Debug)]
52pub enum LocationSide {
53    Lhs,
54    Mutable,
55    Rhs,
56}
57
58#[derive(Debug)]
59pub enum StartOfChainBase {
60    FunctionReference(Function),
61    Variable(VariableRef),
62}
63#[derive(Debug)]
64pub struct Program {
65    pub state: ProgramState,
66    pub modules: Modules,
67    pub default_symbol_table: SymbolTable,
68}
69
70impl Default for Program {
71    fn default() -> Self {
72        Self::new(ProgramState::new(), Modules::new(), SymbolTable::new(&[]))
73    }
74}
75
76impl Program {
77    #[must_use]
78    pub const fn new(
79        state: ProgramState,
80        modules: Modules,
81        default_symbol_table: SymbolTable,
82    ) -> Self {
83        Self {
84            state,
85            modules,
86            default_symbol_table,
87        }
88    }
89}
90
91#[must_use]
92pub const fn convert_span(without: &swamp_ast::SpanWithoutFileId, file_id: FileId) -> Span {
93    Span {
94        file_id,
95        offset: without.offset,
96        length: without.length,
97    }
98}
99
100/// `TypeRef` checking context
101#[derive(Debug, Clone)]
102pub struct TypeContext<'a> {
103    /// Expected type for the current expression
104    pub expected_type: Option<&'a TypeRef>,
105    pub has_lvalue_target: bool,
106}
107
108impl<'a> TypeContext<'a> {
109    #[must_use]
110    pub const fn new(expected_type: Option<&'a TypeRef>, has_lvalue_target: bool) -> Self {
111        Self {
112            expected_type,
113            has_lvalue_target,
114        }
115    }
116
117    pub(crate) const fn with_lvalue(&self) -> Self {
118        Self {
119            expected_type: self.expected_type,
120            has_lvalue_target: true,
121        }
122    }
123
124    pub(crate) const fn argument(&self, expected_type: &'a TypeRef) -> Self {
125        Self {
126            expected_type: Some(expected_type),
127            has_lvalue_target: self.has_lvalue_target,
128        }
129    }
130
131    #[must_use]
132    pub const fn new_argument(required_type: &'a TypeRef, has_lvalue_target: bool) -> Self {
133        Self {
134            expected_type: Some(required_type),
135            has_lvalue_target,
136        }
137    }
138
139    #[must_use]
140    pub const fn new_unsure_argument(
141        expected_type: Option<&'a TypeRef>,
142        has_lvalue_target: bool,
143    ) -> Self {
144        Self {
145            expected_type,
146            has_lvalue_target,
147        }
148    }
149
150    #[must_use]
151    pub const fn new_anything_argument(has_lvalue_target: bool) -> Self {
152        Self {
153            expected_type: None,
154            has_lvalue_target,
155        }
156    }
157
158    #[must_use]
159    pub fn new_function(required_type: &'a TypeRef) -> Self {
160        Self {
161            expected_type: Some(required_type),
162            has_lvalue_target: required_type.collection_view_that_needs_explicit_storage(),
163        }
164    }
165
166    #[must_use]
167    pub const fn with_expected_type(
168        &self,
169        expected_type: Option<&'a TypeRef>,
170        has_lvalue_target: bool,
171    ) -> Self {
172        Self {
173            expected_type,
174            has_lvalue_target,
175        }
176    }
177
178    pub(crate) const fn we_know_expected_type(
179        &self,
180        found_type: &'a TypeRef,
181        has_lvalue_target: bool,
182    ) -> Self {
183        self.with_expected_type(Some(found_type), has_lvalue_target)
184    }
185}
186
187pub struct SharedState<'a> {
188    pub state: &'a mut ProgramState,
189    pub lookup_table: SymbolTable,
190    pub definition_table: SymbolTable,
191    pub modules: &'a Modules,
192    pub source_map: &'a SourceMap,
193    pub file_id: FileId,
194    pub core_symbol_table: SymbolTableRef,
195}
196
197impl<'a> SharedState<'a> {
198    #[must_use]
199    pub fn get_symbol_table(&'a self, path: &[String]) -> Option<&'a SymbolTable> {
200        if path.is_empty() {
201            return Some(&self.lookup_table);
202        }
203        self.get_module(path).map(|module| &module.symbol_table)
204    }
205
206    #[must_use]
207    pub fn get_module(&'a self, path: &[String]) -> Option<&'a ModuleRef> {
208        let resolved_path = {
209            self.lookup_table.get_package_version(&path[0]).map_or_else(
210                || path.to_vec(),
211                |found_version| {
212                    let mut new_path = path.to_vec();
213                    let complete_name = format!("{}-{found_version}", path[0]);
214                    new_path[0] = complete_name;
215                    new_path
216                    //path.to_vec()
217                },
218            )
219        };
220
221        if path.len() == 1 {
222            if let Some(module_ref) = self.lookup_table.get_module_link(&path[0]) {
223                return Some(module_ref);
224            }
225        }
226
227        if let Some(x) = self.modules.get(&resolved_path) {
228            return Some(x);
229        }
230
231        None
232    }
233}
234
235pub struct Analyzer<'a> {
236    pub shared: SharedState<'a>,
237    scope: ScopeInfo,
238    global: FunctionScopeState,
239    module_path: Vec<String>,
240}
241
242impl<'a> Analyzer<'a> {
243    pub fn new(
244        state: &'a mut ProgramState,
245        modules: &'a Modules,
246        core_symbol_table: SymbolTableRef,
247        source_map: &'a SourceMap,
248        module_path: &[String],
249        file_id: FileId,
250    ) -> Self {
251        let shared = SharedState {
252            state,
253            lookup_table: SymbolTable::new(&[]),
254            definition_table: SymbolTable::new(module_path),
255            modules,
256            core_symbol_table,
257            source_map,
258            file_id,
259        };
260        Self {
261            scope: ScopeInfo::default(),
262            global: FunctionScopeState::new(),
263            shared,
264            module_path: module_path.to_vec(),
265        }
266    }
267
268    fn start_function(&mut self) {
269        self.global.block_scope_stack = take(&mut self.scope.active_scope.block_scope_stack);
270        self.scope = ScopeInfo::default();
271    }
272
273    fn stop_function(&mut self) {
274        self.scope.active_scope.block_scope_stack = take(&mut self.global.block_scope_stack);
275    }
276
277    fn analyze_if_expression(
278        &mut self,
279        condition: &swamp_ast::Expression,
280        true_expression: &swamp_ast::Expression,
281        maybe_false_expression: Option<&swamp_ast::Expression>,
282        context: &TypeContext,
283    ) -> Expression {
284        let resolved_condition = self.analyze_bool_argument_expression(condition);
285
286        let branch_context = context;
287
288        let true_expr = self.analyze_expression(true_expression, branch_context);
289        let resolved_true = Box::new(true_expr);
290
291        let mut detected = context.expected_type.cloned();
292        if detected.is_none() {
293            detected = Some(resolved_true.ty.clone());
294        }
295
296        // Analyze the false branch if it exists
297        let else_statements = if let Some(false_expression) = maybe_false_expression {
298            let else_context =
299                branch_context.with_expected_type(detected.as_ref(), context.has_lvalue_target);
300            let else_expr = self.analyze_expression(false_expression, &else_context);
301            if detected.is_none() {
302                detected = Some(else_expr.ty.clone());
303            }
304
305            Some(Box::new(else_expr))
306        } else {
307            None
308        };
309
310        self.create_expr(
311            ExpressionKind::If(resolved_condition, resolved_true, else_statements),
312            detected.unwrap(),
313            &condition.node,
314        )
315    }
316
317    fn get_text(&self, ast_node: &swamp_ast::Node) -> &str {
318        let span = Span {
319            file_id: self.shared.file_id,
320            offset: ast_node.span.offset,
321            length: ast_node.span.length,
322        };
323        self.shared.source_map.get_span_source(
324            self.shared.file_id,
325            span.offset as usize,
326            span.length as usize,
327        )
328    }
329
330    fn get_text_resolved(&self, resolved_node: &Node) -> &str {
331        let span = Span {
332            file_id: self.shared.file_id,
333            offset: resolved_node.span.offset,
334            length: resolved_node.span.length,
335        };
336        self.shared.source_map.get_span_source(
337            self.shared.file_id,
338            span.offset as usize,
339            span.length as usize,
340        )
341    }
342
343    fn get_path(&self, ident: &swamp_ast::QualifiedTypeIdentifier) -> (Vec<String>, String) {
344        let path = ident
345            .module_path
346            .as_ref()
347            .map_or_else(Vec::new, |found_path| {
348                let mut v = Vec::new();
349                for p in &found_path.0 {
350                    v.push(self.get_text(p).to_string());
351                }
352                v
353            });
354        (path, self.get_text(&ident.name.0).to_string())
355    }
356
357    fn analyze_return_type(&mut self, function: &swamp_ast::Function) -> TypeRef {
358        let ast_return_type = match function {
359            swamp_ast::Function::Internal(x) => &x.declaration.return_type,
360            swamp_ast::Function::External(_, x) => &x.return_type,
361        };
362
363        match ast_return_type {
364            None => self.shared.state.types.unit(),
365            Some(x) => self.analyze_type(x),
366        }
367    }
368
369    fn analyze_function_body_expression(
370        &mut self,
371        expression: &swamp_ast::Expression,
372        return_type: &TypeRef,
373    ) -> Expression {
374        let context = TypeContext::new_function(return_type);
375
376        self.analyze_expression(expression, &context)
377    }
378
379    fn analyze_maybe_type(&mut self, maybe_type: Option<&swamp_ast::Type>) -> TypeRef {
380        match maybe_type {
381            None => self.shared.state.types.unit(),
382            Some(ast_type) => self.analyze_type(ast_type),
383        }
384    }
385
386    fn analyze_for_pattern(
387        &mut self,
388        pattern: &swamp_ast::ForPattern,
389        key_type: Option<&TypeRef>,
390        value_type: &TypeRef,
391    ) -> ForPattern {
392        match pattern {
393            swamp_ast::ForPattern::Single(var) => {
394                let variable_ref = self.create_local_variable(
395                    &var.identifier,
396                    Option::from(&var.is_mut),
397                    value_type,
398                    false,
399                );
400                ForPattern::Single(variable_ref)
401            }
402            swamp_ast::ForPattern::Pair(first, second) => {
403                let found_key = key_type.unwrap();
404                let first_var_ref = self.create_local_variable(
405                    &first.identifier,
406                    Option::from(&first.is_mut),
407                    found_key,
408                    false,
409                );
410                let second_var_ref = self.create_local_variable(
411                    &second.identifier,
412                    Option::from(&second.is_mut),
413                    value_type,
414                    false,
415                );
416                ForPattern::Pair(first_var_ref, second_var_ref)
417            }
418        }
419    }
420    const MAX_PARAMETER_COUNT: usize = 6; // NOTE: Must be same or lower than the ABI allows (so it doesn't fail in codegen)
421    fn analyze_parameters(
422        &mut self,
423        parameters: &Vec<swamp_ast::Parameter>,
424    ) -> Vec<TypeForParameter> {
425        let mut resolved_parameters = Vec::new();
426        if parameters.len() > Self::MAX_PARAMETER_COUNT {
427            self.add_err(
428                ErrorKind::TooManyParameters {
429                    encountered: parameters.len(),
430                    allowed: Self::MAX_PARAMETER_COUNT,
431                },
432                &parameters[0].variable.name,
433            );
434            return vec![];
435        }
436        for parameter in parameters {
437            let param_type = self.analyze_type(&parameter.param_type);
438            if !param_type.allowed_as_parameter_type() {
439                self.add_err(
440                    ErrorKind::ParameterTypeCanNotBeStorage(param_type),
441                    &parameter.variable.name,
442                );
443                continue;
444            }
445            resolved_parameters.push(TypeForParameter {
446                name: self.get_text(&parameter.variable.name).to_string(),
447                resolved_type: param_type,
448                is_mutable: parameter.variable.is_mutable.is_some(),
449                node: Some(ParameterNode {
450                    is_mutable: self.to_node_option(Option::from(&parameter.variable.is_mutable)),
451                    name: self.to_node(&parameter.variable.name),
452                }),
453            });
454        }
455        resolved_parameters
456    }
457
458    pub(crate) fn analyze_static_member_access(
459        &mut self,
460        named_type: &swamp_ast::QualifiedTypeIdentifier,
461        member_name_node: &swamp_ast::Node,
462    ) -> Option<Function> {
463        if let Some(found_function) = self.special_static_member(named_type, member_name_node) {
464            Some(found_function)
465        } else {
466            let some_type = self.analyze_named_type(named_type);
467
468            let member_name = self.get_text(member_name_node);
469            self.lookup_associated_function(&some_type, member_name)
470        }
471    }
472
473    pub fn analyze_local_function_access(
474        &mut self,
475        qualified_func_name: &swamp_ast::QualifiedIdentifier,
476    ) -> Option<Function> {
477        let path = self.get_module_path(qualified_func_name.module_path.as_ref());
478        let function_name = self.get_text(&qualified_func_name.name);
479
480        if let Some(found_table) = self.shared.get_symbol_table(&path) {
481            if let Some(found_func) = found_table.get_function(function_name) {
482                let (kind, signature) = match found_func {
483                    FuncDef::Internal(internal_fn) => (
484                        Function::Internal(internal_fn.clone()),
485                        &internal_fn.signature,
486                    ),
487                    FuncDef::External(external_fn) => (
488                        Function::External(external_fn.clone()),
489                        &external_fn.signature,
490                    ),
491                    // Can not have a reference to an intrinsic function
492                    FuncDef::Intrinsic(intrinsic_fn) => (
493                        Function::Intrinsic(intrinsic_fn.clone()),
494                        &intrinsic_fn.signature,
495                    ),
496                };
497
498                return Some(kind);
499            }
500        }
501
502        None
503    }
504
505    fn check_if_function_reference(
506        &mut self,
507        ast_expression: &swamp_ast::Expression,
508    ) -> Option<Function> {
509        match &ast_expression.kind {
510            swamp_ast::ExpressionKind::StaticMemberFunctionReference(
511                qualified_type_identifier,
512                node,
513            ) => self.analyze_static_member_access(qualified_type_identifier, node),
514            swamp_ast::ExpressionKind::IdentifierReference(qualified_identifier) => {
515                self.analyze_local_function_access(qualified_identifier)
516            }
517            _ => None,
518        }
519    }
520
521    /// # Errors
522    ///
523    pub fn analyze_start_chain_expression_get_mutability(
524        &mut self,
525        ast_expression: &swamp_ast::Expression,
526    ) -> Option<StartOfChainBase> {
527        self.check_if_function_reference(ast_expression)
528            .map_or_else(
529                || {
530                    if let swamp_ast::ExpressionKind::IdentifierReference(
531                        found_qualified_identifier,
532                    ) = &ast_expression.kind
533                    {
534                        self.try_find_variable(&found_qualified_identifier.name)
535                            .map(StartOfChainBase::Variable)
536                    } else {
537                        None
538                    }
539                },
540                |found_func_def| Some(StartOfChainBase::FunctionReference(found_func_def)),
541            )
542    }
543
544    pub fn debug_expression(&self, expr: &swamp_ast::Expression, description: &str) {
545        self.debug_line(expr.node.span.offset as usize, description);
546    }
547
548    pub fn debug_line(&self, offset: usize, description: &str) {
549        let (line, col) = self
550            .shared
551            .source_map
552            .get_span_location_utf8(self.shared.file_id, offset);
553
554        let source_line = self
555            .shared
556            .source_map
557            .get_source_line(self.shared.file_id, line);
558
559        let source_path = self
560            .shared
561            .source_map
562            .fetch_relative_filename(self.shared.file_id);
563        let debug_line = format!("{source_path}:{line}:{col}> {}", source_line.unwrap());
564        //info!(%debug_line, "source");
565
566        //        info!(?line, ?col, "source reference");
567    }
568
569    /// # Errors
570    ///
571    pub fn analyze_main_expression(
572        &mut self,
573        ast_expression: &swamp_ast::Expression,
574    ) -> InternalMainExpression {
575        self.start_function();
576
577        let context = TypeContext::new_anything_argument(true); // function returns are per definition lvalue target for aggregates
578        let analyzed_expr = self.analyze_expression(ast_expression, &context);
579        let main_expr = InternalMainExpression {
580            expression: analyzed_expr,
581            scopes: self.scope.total_scopes.clone(),
582            program_unique_id: self.shared.state.allocate_internal_function_id(),
583        };
584
585        self.stop_function();
586
587        main_expr
588    }
589
590    fn analyze_maybe_ref_expression(
591        &mut self,
592        ast_expr: &swamp_ast::Expression,
593    ) -> MaybeBorrowMutRefExpression {
594        if let swamp_ast::ExpressionKind::UnaryOp(found_unary, ast_inner_expression) =
595            &ast_expr.kind
596        {
597            if let swamp_ast::UnaryOperator::BorrowMutRef(node) = found_unary {
598                //let inner = self.analyze_expression(ast_inner_expression, context)?;
599                let resolved_node = self.to_node(node);
600                return MaybeBorrowMutRefExpression {
601                    ast_expression: *ast_inner_expression.clone(),
602                    has_borrow_mutable_reference: Some(resolved_node),
603                };
604            }
605        }
606
607        MaybeBorrowMutRefExpression {
608            ast_expression: ast_expr.clone(),
609            has_borrow_mutable_reference: None,
610        }
611    }
612
613    /// Check if an expression needs explicit storage and should return an error
614    fn needs_storage_error(
615        &self,
616        expr: &Expression,
617        is_function_call: bool,
618        context: &TypeContext,
619        ast_node: &swamp_ast::Node,
620    ) -> bool {
621        let is_constant = matches!(expr.kind, ExpressionKind::ConstantAccess(_));
622        let is_variable = matches!(expr.kind, ExpressionKind::VariableAccess(_));
623
624        // Return true if we need to create an error
625        !context.has_lvalue_target
626            && expr.ty.collection_view_that_needs_explicit_storage()
627            && is_function_call
628            && !is_constant
629            && !is_variable
630    }
631
632    pub fn analyze_expression(
633        &mut self,
634        ast_expression: &swamp_ast::Expression,
635        context: &TypeContext,
636    ) -> Expression {
637        //info!(?ast_expression, "analyze expression");
638        //self.debug_expression(ast_expression, "analyze");
639        let expr = self.analyze_expression_internal(ast_expression, context);
640
641        if matches!(expr.kind, ExpressionKind::Error(_)) {
642            return expr;
643        }
644
645        let encountered_type = expr.ty.clone();
646
647        //info!(?expr, "analyze expression");
648        let expr = if let Some(found_expected_type) = context.expected_type {
649            let reduced_expected = found_expected_type;
650
651            let reduced_encountered_type = encountered_type;
652
653            if self
654                .shared
655                .state
656                .types
657                .compatible_with(reduced_expected, &reduced_encountered_type)
658            {
659                expr
660            } else {
661                self.types_did_not_match_try_late_coerce_expression(
662                    expr,
663                    reduced_expected,
664                    &reduced_encountered_type,
665                    &ast_expression.node,
666                )
667            }
668        } else {
669            expr
670            //todo!()
671            // TODO: self.coerce_unrestricted_type(&ast_expression.node, expr)?
672        };
673
674        // Only apply storage rule to function calls that return types needing explicit storage
675        // Exclude literals, constants, and variables which already have storage or are constructed directly
676        let is_function_call = Self::is_aggregate_function_call(ast_expression);
677
678        if self.needs_storage_error(&expr, is_function_call, context, &ast_expression.node) {
679            // We have no way to store it
680            self.create_err(ErrorKind::NeedStorage, &ast_expression.node)
681        } else {
682            expr
683        }
684    }
685
686    /// # Errors
687    ///
688    #[allow(clippy::too_many_lines)]
689    pub fn analyze_expression_internal(
690        &mut self,
691        ast_expression: &swamp_ast::Expression,
692        context: &TypeContext,
693    ) -> Expression {
694        //info!(ty=%expression.ty, kind=?expression.kind,  "resolved expression");
695
696        match &ast_expression.kind {
697            // Lookups
698            swamp_ast::ExpressionKind::PostfixChain(postfix_chain) => {
699                self.analyze_postfix_chain(postfix_chain, context)
700            }
701
702            swamp_ast::ExpressionKind::VariableDefinition(
703                variable,
704                maybe_annotation,
705                source_expression,
706            ) => self.analyze_create_variable(
707                variable,
708                Option::from(maybe_annotation),
709                source_expression,
710            ),
711
712            swamp_ast::ExpressionKind::VariableAssignment(variable, source_expression) => {
713                self.analyze_variable_assignment(variable, source_expression)
714            }
715
716            swamp_ast::ExpressionKind::DestructuringAssignment(variables, expression) => {
717                self.analyze_destructuring(&ast_expression.node, variables, expression)
718            }
719
720            swamp_ast::ExpressionKind::IdentifierReference(qualified_identifier) => {
721                self.analyze_identifier(qualified_identifier)
722            }
723
724            swamp_ast::ExpressionKind::VariableReference(variable) => {
725                self.analyze_variable_reference(&variable.name)
726            }
727
728            swamp_ast::ExpressionKind::ContextAccess => {
729                todo!("context access is not done yet")
730            }
731
732            swamp_ast::ExpressionKind::StaticMemberFunctionReference(
733                type_identifier,
734                member_name,
735            ) => {
736                let debug_name = self.get_text(member_name);
737                let type_name = self.get_text(&type_identifier.name.0);
738                panic!("can not have separate member func ref {type_name:?} {debug_name}")
739            }
740
741            swamp_ast::ExpressionKind::ConstantReference(constant_identifier) => {
742                self.analyze_constant_access(constant_identifier)
743            }
744
745            swamp_ast::ExpressionKind::Assignment(location, source) => {
746                self.analyze_assignment(location, source)
747            }
748
749            swamp_ast::ExpressionKind::CompoundAssignment(target, op, source) => {
750                self.analyze_assignment_compound(target, op, source)
751            }
752
753            // Operator
754            swamp_ast::ExpressionKind::BinaryOp(resolved_a, operator, resolved_b) => {
755                let Some((resolved_op, result_type)) =
756                    self.analyze_binary_op(resolved_a, operator, resolved_b)
757                else {
758                    return self.create_err(ErrorKind::OperatorProblem, &operator.node);
759                };
760
761                self.create_expr(
762                    ExpressionKind::BinaryOp(resolved_op),
763                    result_type,
764                    &ast_expression.node,
765                )
766            }
767
768            swamp_ast::ExpressionKind::UnaryOp(operator, expression) => {
769                if let swamp_ast::UnaryOperator::BorrowMutRef(_node) = operator {
770                    let inner_expr =
771                        self.analyze_to_location(expression, context, LocationSide::Rhs);
772                    let ty = inner_expr.ty.clone();
773                    self.create_expr(
774                        ExpressionKind::BorrowMutRef(Box::from(inner_expr)),
775                        ty,
776                        &ast_expression.node,
777                    )
778                } else {
779                    let Some((resolved_op, result_type)) =
780                        self.analyze_unary_op(operator, expression)
781                    else {
782                        return self.create_err(ErrorKind::OperatorProblem, &ast_expression.node);
783                    };
784                    self.create_expr(
785                        ExpressionKind::UnaryOp(resolved_op),
786                        result_type,
787                        &ast_expression.node,
788                    )
789                }
790            }
791
792            swamp_ast::ExpressionKind::Block(expressions) => {
793                let (block, resulting_type) =
794                    self.analyze_block(&ast_expression.node, context, expressions);
795                self.create_expr(
796                    ExpressionKind::Block(block),
797                    resulting_type,
798                    &ast_expression.node,
799                )
800            }
801
802            swamp_ast::ExpressionKind::With(variable_bindings, expression) => {
803                self.analyze_with_expr(context, variable_bindings, expression)
804            }
805
806            swamp_ast::ExpressionKind::When(variable_bindings, true_expr, else_expr) => {
807                self.analyze_when_expr(context, variable_bindings, true_expr, else_expr.as_deref())
808            }
809
810            swamp_ast::ExpressionKind::InterpolatedString(string_parts) => {
811                self.analyze_interpolated_string_lowering(&ast_expression.node, string_parts)
812            }
813
814            // Creation
815            swamp_ast::ExpressionKind::NamedStructLiteral(struct_identifier, fields, has_rest) => {
816                self.analyze_named_struct_literal(struct_identifier, fields, *has_rest)
817            }
818
819            swamp_ast::ExpressionKind::AnonymousStructLiteral(fields, rest_was_specified) => self
820                .analyze_anonymous_struct_literal(
821                    &ast_expression.node,
822                    fields,
823                    *rest_was_specified,
824                    context,
825                ),
826
827            swamp_ast::ExpressionKind::ContextAccess => {
828                todo!("lone dot not implemented yet")
829            }
830
831            swamp_ast::ExpressionKind::Range(min_value, max_value, range_mode) => {
832                self.analyze_range(min_value, max_value, range_mode, &ast_expression.node)
833            }
834
835            swamp_ast::ExpressionKind::ForLoop(pattern, iterable_expression, statements) => {
836                if pattern.is_key_variable_mut() {
837                    return self.create_err(
838                        ErrorKind::KeyVariableNotAllowedToBeMutable,
839                        &ast_expression.node,
840                    );
841                }
842                let resolved_iterator =
843                    self.analyze_iterable(pattern.is_value_mut(), &iterable_expression.expression);
844
845                self.push_block_scope("for_loop");
846                let pattern = self.analyze_for_pattern(
847                    pattern,
848                    resolved_iterator.key_type.as_ref(),
849                    &resolved_iterator.value_type,
850                );
851                let resolved_statements = self.analyze_expression(statements, context);
852                self.pop_block_scope("for_loop");
853                let resolved_type = resolved_statements.ty.clone();
854                self.create_expr(
855                    ExpressionKind::ForLoop(
856                        pattern,
857                        resolved_iterator,
858                        Box::from(resolved_statements),
859                    ),
860                    resolved_type,
861                    &ast_expression.node,
862                )
863            }
864
865            swamp_ast::ExpressionKind::WhileLoop(expression, statements) => {
866                let condition = self.analyze_bool_argument_expression(expression);
867                //self.push_block_scope("while_loop");
868                let resolved_statements = self.analyze_expression(statements, context);
869                let resolved_type = resolved_statements.ty.clone();
870                //self.pop_block_scope("while_loop");
871
872                self.create_expr(
873                    ExpressionKind::WhileLoop(condition, Box::from(resolved_statements)),
874                    resolved_type,
875                    &ast_expression.node,
876                )
877            }
878
879            swamp_ast::ExpressionKind::If(expression, true_expression, maybe_false_expression) => {
880                self.analyze_if_expression(
881                    expression,
882                    true_expression,
883                    maybe_false_expression.as_deref(),
884                    context,
885                )
886            }
887
888            swamp_ast::ExpressionKind::Match(expression, arms) => {
889                let (match_expr, return_type) = self.analyze_match(expression, context, arms);
890                self.create_expr(
891                    ExpressionKind::Match(match_expr),
892                    return_type,
893                    &ast_expression.node,
894                )
895            }
896            swamp_ast::ExpressionKind::Guard(guard_expressions) => {
897                self.analyze_guard(&ast_expression.node, context, guard_expressions)
898            }
899
900            swamp_ast::ExpressionKind::Lambda(variables, expression) => {
901                self.analyze_lambda(&ast_expression.node, variables, expression, context)
902            }
903            swamp_ast::ExpressionKind::Error => {
904                self.create_err(ErrorKind::UnexpectedType, &ast_expression.node)
905            }
906            swamp_ast::ExpressionKind::Literal(literal) => {
907                self.analyze_complex_literal_to_expression(ast_expression, literal, context)
908            } //self.create_err(ErrorKind::UnexpectedType, &ast_expression.node),
909        }
910    }
911
912    fn get_struct_type(
913        &mut self,
914        qualified_type_identifier: &swamp_ast::QualifiedTypeIdentifier,
915    ) -> NamedStructType {
916        let maybe_struct_type = self.analyze_named_type(qualified_type_identifier);
917        if let TypeKind::NamedStruct(struct_type) = &*maybe_struct_type.kind {
918            struct_type.clone()
919        } else {
920            self.add_err(
921                // For other TypeRef variants that are not Struct
922                ErrorKind::UnknownStructTypeReference,
923                &qualified_type_identifier.name.0,
924            );
925
926            NamedStructType {
927                name: Default::default(),
928                module_path: vec![],
929                assigned_name: String::new(),
930                anon_struct_type: self.types().unit(),
931                instantiated_type_parameters: vec![],
932            }
933        }
934    }
935
936    pub(crate) fn analyze_named_type(
937        &mut self,
938        type_name_to_find: &swamp_ast::QualifiedTypeIdentifier,
939    ) -> TypeRef {
940        let (path, name) = self.get_path(type_name_to_find);
941        let mut analyzed_type_parameters = Vec::new();
942
943        if let Some(found) =
944            self.analyze_special_named_type(&path, &name, &type_name_to_find.generic_params)
945        {
946            return found;
947        }
948
949        for analyzed_type in &type_name_to_find.generic_params {
950            let ty = self.analyze_type(analyzed_type.get_type());
951
952            analyzed_type_parameters.push(ty);
953        }
954
955        let symbol = {
956            if let Some(symbol_table) = self.shared.get_symbol_table(&path) {
957                if let Some(x) = symbol_table.get_symbol(&name) {
958                    x
959                } else {
960                    self.add_err(ErrorKind::UnknownSymbol, &type_name_to_find.name.0);
961                    return self.types().unit();
962                }
963            } else {
964                self.add_err(ErrorKind::UnexpectedType, &type_name_to_find.name.0);
965                return self.types().unit();
966            }
967        };
968
969        if analyzed_type_parameters.is_empty() {
970            match &symbol {
971                Symbol::Type(base_type) => base_type.clone(),
972                Symbol::Alias(alias_type) => alias_type.ty.clone(),
973                _ => {
974                    self.add_err(ErrorKind::UnexpectedType, &type_name_to_find.name.0);
975                    self.types().unit()
976                }
977            }
978        } else {
979            panic!("unknown type")
980        }
981    }
982
983    fn create_default_value_for_type(
984        &mut self,
985        node: &swamp_ast::Node,
986        field_type: &TypeRef,
987    ) -> Option<Expression> {
988        let kind = match &*field_type.kind {
989            TypeKind::Tuple(tuple_type_ref) => {
990                let mut expressions = Vec::new();
991                for resolved_type in tuple_type_ref {
992                    let expr = self.create_default_value_for_type(node, resolved_type)?;
993                    expressions.push(expr);
994                }
995                ExpressionKind::TupleLiteral(expressions)
996            }
997
998            TypeKind::NamedStruct(_struct_ref) => {
999                // Only call default() if the type actually has a default implementation
1000                if self
1001                    .shared
1002                    .state
1003                    .associated_impls
1004                    .get_member_function(field_type, "default")
1005                    .is_some()
1006                {
1007                    self.create_default_static_call(node, field_type)
1008                } else {
1009                    // This type doesn't have a default implementation, skip it
1010                    return None;
1011                }
1012            }
1013
1014            _ => {
1015                // For primitives and other types without default implementations, skip them
1016                return None;
1017            }
1018        };
1019
1020        Some(self.create_expr(kind, field_type.clone(), node))
1021    }
1022
1023    fn create_static_member_call(
1024        &mut self,
1025        function_name: &str,
1026        arguments: &[ArgumentExpression],
1027        node: &swamp_ast::Node,
1028        ty: &TypeRef,
1029    ) -> ExpressionKind {
1030        self.lookup_associated_function(ty, function_name)
1031            .map_or_else(
1032                || {
1033                    self.create_err(
1034                        ErrorKind::NoAssociatedFunction(ty.clone(), function_name.to_string()),
1035                        node,
1036                    )
1037                        .kind
1038                },
1039                |function| {
1040                    let Function::Internal(internal_function) = &function else {
1041                        panic!("only allowed for internal functions");
1042                    };
1043
1044                    ExpressionKind::InternalCall(internal_function.clone(), arguments.to_vec())
1045                },
1046            )
1047    }
1048
1049    fn create_static_member_intrinsic_call(
1050        &mut self,
1051        function_name: &str,
1052        arguments: &[ArgumentExpression],
1053        node: &swamp_ast::Node,
1054        ty: &TypeRef,
1055    ) -> ExpressionKind {
1056        // Look up the function first to avoid closure borrowing issues
1057        if let Some(function) = self.lookup_associated_function(ty, function_name) {
1058            let Function::Internal(internal_function) = &function else {
1059                panic!("only allowed for internal functions");
1060            };
1061
1062            if let Some((intrinsic_fn, _)) =
1063                Self::extract_single_intrinsic_call(&internal_function.body)
1064            {
1065                ExpressionKind::IntrinsicCallEx(intrinsic_fn, arguments.to_vec())
1066            } else {
1067                self.create_err(
1068                    ErrorKind::NoAssociatedFunction(ty.clone(), function_name.to_string()),
1069                    node,
1070                )
1071                    .kind
1072            }
1073        } else {
1074            self.create_err(
1075                ErrorKind::NoAssociatedFunction(ty.clone(), function_name.to_string()),
1076                node,
1077            )
1078                .kind
1079        }
1080    }
1081
1082    fn create_default_static_call(
1083        &mut self,
1084        node: &swamp_ast::Node,
1085        ty: &TypeRef,
1086    ) -> ExpressionKind {
1087        self.create_static_member_call("default", &[], node, ty)
1088    }
1089
1090    fn add_postfix(
1091        &mut self,
1092        vec: &mut Vec<Postfix>,
1093        kind: PostfixKind,
1094        ty: TypeRef,
1095        node: &swamp_ast::Node,
1096    ) {
1097        let resolved_node = self.to_node(node);
1098        let postfix = Postfix {
1099            node: resolved_node,
1100            ty,
1101            kind,
1102        };
1103
1104        vec.push(postfix);
1105    }
1106
1107    /// # Panics
1108    ///
1109    /// # Errors
1110    ///
1111    pub fn analyze_struct_field(
1112        &mut self,
1113        field_name: &swamp_ast::Node,
1114        tv: &TypeRef,
1115    ) -> (AnonymousStructType, usize, TypeRef) {
1116        let field_name_str = self.get_text(field_name).to_string();
1117
1118        let anon_struct_ref = match &*tv.kind {
1119            TypeKind::NamedStruct(struct_type) => struct_type.anon_struct_type.clone(),
1120            TypeKind::AnonymousStruct(anon_struct) => {
1121                // Create a TypeRef from the AnonymousStructType
1122                self.shared
1123                    .state
1124                    .types
1125                    .anonymous_struct(anon_struct.clone())
1126            }
1127            TypeKind::Range(range_struct_ref) => {
1128                // Extract NamedStructType from TypeRef, then AnonymousStructType from that
1129                if let TypeKind::NamedStruct(named_struct) = &*range_struct_ref.kind {
1130                    named_struct.anon_struct_type.clone()
1131                } else {
1132                    self.add_err(ErrorKind::UnknownStructField, field_name);
1133                    // Return fallback values
1134                    return (
1135                        AnonymousStructType::new(SeqMap::new()),
1136                        0,
1137                        self.shared.state.types.unit(),
1138                    );
1139                }
1140            }
1141            _ => {
1142                self.add_err(ErrorKind::UnknownStructField, field_name);
1143                // Return fallback values
1144                return (
1145                    AnonymousStructType::new(SeqMap::new()),
1146                    0,
1147                    self.shared.state.types.unit(),
1148                );
1149            }
1150        };
1151
1152        // Extract the AnonymousStructType from the TypeRef
1153        if let TypeKind::AnonymousStruct(anon_struct) = &*anon_struct_ref.kind {
1154            if let Some(found_field) = anon_struct.field_name_sorted_fields.get(&field_name_str) {
1155                let index = anon_struct
1156                    .field_name_sorted_fields
1157                    .get_index(&field_name_str)
1158                    .expect("checked earlier");
1159
1160                return (anon_struct.clone(), index, found_field.field_type.clone());
1161            }
1162        }
1163
1164        self.add_err(ErrorKind::UnknownStructField, field_name);
1165        // Return fallback values
1166        (
1167            AnonymousStructType::new(SeqMap::new()),
1168            0,
1169            self.shared.state.types.unit(),
1170        )
1171    }
1172
1173    pub fn analyze_static_call(
1174        &mut self,
1175        ast_node: &swamp_ast::Node,
1176        maybe_associated_to_type: Option<TypeRef>,
1177        func_def: Function,
1178        maybe_generic_arguments: &Option<Vec<swamp_ast::GenericParameter>>,
1179        arguments: &[swamp_ast::Expression],
1180        context: &TypeContext,
1181    ) -> Expression {
1182        let signature = func_def.signature().clone();
1183
1184        let analyzed_arguments =
1185            self.analyze_and_verify_parameters(ast_node, &signature.parameters, arguments);
1186
1187        let expr_kind = match &func_def {
1188            Function::Internal(internal) => {
1189                ExpressionKind::InternalCall(internal.clone(), analyzed_arguments)
1190            }
1191            Function::External(host) => ExpressionKind::HostCall(host.clone(), analyzed_arguments),
1192            Function::Intrinsic(intrinsic) => {
1193                ExpressionKind::IntrinsicCallEx(intrinsic.intrinsic.clone(), analyzed_arguments)
1194            }
1195        };
1196
1197        let expr = self.create_expr(expr_kind, signature.return_type.clone(), ast_node);
1198
1199        // Check if function returns a type that needs explicit storage and we don't have an lvalue target
1200        if self.needs_storage_error(&expr, true, context, ast_node) {
1201            return self.create_err(ErrorKind::NeedStorage, ast_node);
1202        }
1203
1204        expr
1205    }
1206
1207    #[allow(clippy::too_many_lines)]
1208    fn analyze_postfix_chain(
1209        &mut self,
1210        chain: &swamp_ast::PostfixChain,
1211        context: &TypeContext,
1212    ) -> Expression {
1213        let maybe_start_of_chain_base =
1214            self.analyze_start_chain_expression_get_mutability(&chain.base);
1215
1216        let mut start_index = 0;
1217
1218        let start_of_chain_kind = if let Some(start_of_chain_base) = maybe_start_of_chain_base {
1219            //trace!(?start_of_chain_base, "start of postfix chain");
1220            match start_of_chain_base {
1221                StartOfChainBase::FunctionReference(func_def) => {
1222                    // In this language version, it is not allowed to provide references to functions
1223                    // So it must mean that this is a function call
1224                    if let swamp_ast::Postfix::FunctionCall(
1225                        ast_node,
1226                        maybe_generic_arguments,
1227                        arguments,
1228                    ) = &chain.postfixes[0]
1229                    {
1230                        start_index = 1;
1231                        let call_expr = self.analyze_static_call(
1232                            ast_node,
1233                            None,
1234                            func_def,
1235                            maybe_generic_arguments,
1236                            arguments,
1237                            context,
1238                        );
1239                        if chain.postfixes.len() == 1 {
1240                            return call_expr;
1241                        }
1242                        StartOfChainKind::Expression(Box::from(call_expr))
1243                    } else {
1244                        panic!("must be a normal function call")
1245                    }
1246                }
1247                StartOfChainBase::Variable(var) => StartOfChainKind::Variable(var),
1248            }
1249        } else {
1250            let ctx = TypeContext::new_anything_argument(true); // we will allocate space for the starting point
1251            StartOfChainKind::Expression(Box::from(self.analyze_expression(&chain.base, &ctx)))
1252        };
1253
1254        let start_of_chain_node = self.to_node(&chain.base.node);
1255
1256        let start_of_chain = StartOfChain {
1257            kind: start_of_chain_kind.clone(),
1258            node: start_of_chain_node,
1259        };
1260
1261        let mut tv = TypeWithMut {
1262            resolved_type: start_of_chain_kind.ty(),
1263            is_mutable: start_of_chain_kind.is_mutable(),
1264        };
1265
1266        let mut uncertain = false;
1267
1268        let mut suffixes = Vec::new();
1269
1270        for (index, item) in chain.postfixes[start_index..].iter().enumerate() {
1271            //            trace!(?item, "postfix");
1272            let is_last = index == chain.postfixes[start_index..].len() - 1;
1273
1274            match item {
1275                /*
1276                swamp_ast::Postfix::AdvancedFunctionCall(..) => {
1277                    todo!("AdvancedFunctionCall")
1278                }
1279
1280                 */
1281                swamp_ast::Postfix::FieldAccess(field_name) => {
1282                    let (struct_type_ref, index, return_type) =
1283                        self.analyze_struct_field(&field_name.clone(), &tv.resolved_type);
1284                    let struct_type_type_ref = self
1285                        .shared
1286                        .state
1287                        .types
1288                        .anonymous_struct(struct_type_ref.clone());
1289                    self.add_postfix(
1290                        &mut suffixes,
1291                        PostfixKind::StructField(struct_type_type_ref, index),
1292                        return_type.clone(),
1293                        field_name,
1294                    );
1295
1296                    tv.resolved_type = return_type.clone();
1297                    // keep previous `is_mutable`
1298                }
1299
1300                swamp_ast::Postfix::SubscriptTuple(col_expr, row_expr) => {
1301                    let collection_type = tv.resolved_type.clone();
1302                    match &*collection_type.kind {
1303                        TypeKind::GridStorage(element_type, x, _) => {
1304                            let int_type = self.shared.state.types.int();
1305                            let unsigned_int_x_context =
1306                                TypeContext::new_argument(&int_type, false);
1307                            let unsigned_int_x_expression =
1308                                self.analyze_expression(col_expr, &unsigned_int_x_context);
1309
1310                            let unsigned_int_y_context =
1311                                TypeContext::new_argument(&int_type, false);
1312                            let unsigned_int_y_expression =
1313                                self.analyze_expression(row_expr, &unsigned_int_y_context);
1314
1315                            let vec_type = GridType {
1316                                element: element_type.clone(),
1317                            };
1318
1319                            self.add_postfix(
1320                                &mut suffixes,
1321                                PostfixKind::GridSubscript(
1322                                    vec_type,
1323                                    unsigned_int_x_expression,
1324                                    unsigned_int_y_expression,
1325                                ),
1326                                element_type.clone(),
1327                                &col_expr.node,
1328                            );
1329
1330                            // Keep previous mutable
1331                            tv.resolved_type = element_type.clone();
1332                        }
1333                        _ => panic!("not a subscript tuple"),
1334                    }
1335                }
1336
1337                swamp_ast::Postfix::Subscript(lookup_expr) => {
1338                    let collection_type = tv.resolved_type.clone();
1339                    match &*collection_type.kind {
1340                        TypeKind::FixedCapacityAndLengthArray(element_type_in_slice, _) => {
1341                            let int_type = self.shared.state.types.int();
1342                            let unsigned_int_context = TypeContext::new_argument(&int_type, false);
1343                            let unsigned_int_expression =
1344                                self.analyze_expression(lookup_expr, &unsigned_int_context);
1345
1346                            let slice_type = SliceViewType {
1347                                element: element_type_in_slice.clone(),
1348                            };
1349
1350                            self.add_postfix(
1351                                &mut suffixes,
1352                                PostfixKind::SliceViewSubscript(
1353                                    slice_type,
1354                                    unsigned_int_expression,
1355                                ),
1356                                collection_type.clone(),
1357                                &lookup_expr.node,
1358                            );
1359
1360                            // Keep previous mutable
1361                            tv.resolved_type = element_type_in_slice.clone();
1362                        }
1363                        TypeKind::QueueStorage(element_type, _)
1364                        | TypeKind::StackStorage(element_type, _)
1365                        | TypeKind::StackView(element_type)
1366                        | TypeKind::VecStorage(element_type, _)
1367                        | TypeKind::StringStorage(element_type, _, _)
1368                        | TypeKind::String(element_type, _)
1369                        | TypeKind::DynamicLengthVecView(element_type)
1370                        | TypeKind::SliceView(element_type) => {
1371                            let int_type = self.shared.state.types.int();
1372                            let unsigned_int_context = TypeContext::new_argument(&int_type, false);
1373                            let unsigned_int_expression =
1374                                self.analyze_expression(lookup_expr, &unsigned_int_context);
1375
1376                            let vec_type = VecType {
1377                                element: element_type.clone(),
1378                            };
1379
1380                            self.add_postfix(
1381                                &mut suffixes,
1382                                PostfixKind::VecSubscript(vec_type, unsigned_int_expression),
1383                                element_type.clone(),
1384                                &lookup_expr.node,
1385                            );
1386
1387                            // Keep previous mutable
1388                            tv.resolved_type = element_type.clone();
1389                        }
1390                        TypeKind::SparseStorage(element_type, _)
1391                        | TypeKind::SparseView(element_type) => {
1392                            let int_type = self.shared.state.types.int();
1393                            let unsigned_int_context = TypeContext::new_argument(&int_type, false);
1394                            let unsigned_int_expression =
1395                                self.analyze_expression(lookup_expr, &unsigned_int_context);
1396
1397                            let vec_type = SparseType {
1398                                element: element_type.clone(),
1399                            };
1400
1401                            self.add_postfix(
1402                                &mut suffixes,
1403                                PostfixKind::SparseSubscript(vec_type, unsigned_int_expression),
1404                                element_type.clone(),
1405                                &lookup_expr.node,
1406                            );
1407
1408                            // Keep previous mutable
1409                            tv.resolved_type = element_type.clone();
1410                        }
1411                        TypeKind::MapStorage(key_type, value_type, _)
1412                        | TypeKind::DynamicLengthMapView(key_type, value_type) => {
1413                            let key_context = TypeContext::new_argument(key_type, false);
1414                            let key_expression = self.analyze_expression(lookup_expr, &key_context);
1415
1416                            let map_type = MapType {
1417                                key: key_type.clone(),
1418                                value: value_type.clone(),
1419                            };
1420
1421                            self.add_postfix(
1422                                &mut suffixes,
1423                                PostfixKind::MapSubscript(map_type, key_expression),
1424                                value_type.clone(),
1425                                &lookup_expr.node,
1426                            );
1427
1428                            // Keep previous mutable
1429                            tv.resolved_type = value_type.clone();
1430                        }
1431                        _ => {
1432                            eprintln!("xwhat is this: {collection_type:?}");
1433                            return self
1434                                .create_err(ErrorKind::MissingSubscriptMember, &lookup_expr.node);
1435                        }
1436                    }
1437                }
1438
1439                swamp_ast::Postfix::MemberCall(member_name, generic_arguments, ast_arguments) => {
1440                    let member_name_str = self.get_text(member_name).to_string();
1441                    let underlying_type = tv.resolved_type;
1442
1443                    let (kind, return_type) = self.analyze_member_call(
1444                        &underlying_type,
1445                        &member_name_str,
1446                        generic_arguments.clone(),
1447                        ast_arguments,
1448                        tv.is_mutable,
1449                        member_name,
1450                    );
1451
1452                    self.add_postfix(&mut suffixes, kind, return_type.clone(), member_name);
1453                    tv.resolved_type = return_type.clone();
1454                    tv.is_mutable = false;
1455                }
1456                swamp_ast::Postfix::FunctionCall(node, _generic_arguments, arguments) => {
1457                    panic!("can only have function call at the start of a postfix chain")
1458                }
1459
1460                swamp_ast::Postfix::NoneCoalescingOperator(default_expr) => {
1461                    let unwrapped_type = if let TypeKind::Optional(unwrapped_type) =
1462                        &*tv.resolved_type.kind
1463                    {
1464                        unwrapped_type
1465                    } else if uncertain {
1466                        &tv.resolved_type
1467                    } else {
1468                        return self.create_err(ErrorKind::CanNotNoneCoalesce, &default_expr.node);
1469                    };
1470
1471                    let unwrapped_type_context = TypeContext::new_argument(unwrapped_type, false);
1472                    let resolved_default_expr =
1473                        self.analyze_expression(default_expr, &unwrapped_type_context);
1474                    self.add_postfix(
1475                        &mut suffixes,
1476                        PostfixKind::NoneCoalescingOperator(resolved_default_expr),
1477                        (*unwrapped_type).clone(),
1478                        &default_expr.node,
1479                    );
1480                    tv.resolved_type = (*unwrapped_type).clone();
1481                    uncertain = false; // the chain is safe, because this will always solve None
1482                }
1483
1484                swamp_ast::Postfix::OptionalChainingOperator(option_node) => {
1485                    if is_last {
1486                        return self.create_err(
1487                            ErrorKind::OptionalChainingOperatorCanNotBePartOfChain,
1488                            option_node,
1489                        );
1490                    }
1491
1492                    if let TypeKind::Optional(unwrapped_type) = &*tv.resolved_type.kind {
1493                        uncertain = true;
1494                        self.add_postfix(
1495                            &mut suffixes,
1496                            PostfixKind::OptionalChainingOperator,
1497                            (*unwrapped_type).clone(),
1498                            option_node,
1499                        );
1500                        tv.resolved_type = (*unwrapped_type).clone();
1501                    } else {
1502                        return self.create_err(ErrorKind::ExpectedOptional, option_node);
1503                    }
1504                }
1505            }
1506        }
1507
1508        if uncertain {
1509            if let TypeKind::Optional(_) = &*tv.resolved_type.kind {} else {
1510                tv.resolved_type = self.shared.state.types.optional(&tv.resolved_type.clone());
1511            }
1512        }
1513
1514        self.create_expr(
1515            ExpressionKind::PostfixChain(start_of_chain, suffixes),
1516            tv.resolved_type,
1517            &chain.base.node,
1518        )
1519    }
1520
1521    fn analyze_bool_argument_expression(
1522        &mut self,
1523        expression: &swamp_ast::Expression,
1524    ) -> BooleanExpression {
1525        let bool_type = self.shared.state.types.bool();
1526        let bool_context = TypeContext::new_argument(&bool_type, false);
1527        let resolved_expression = self.analyze_expression(expression, &bool_context);
1528        let expr_type = resolved_expression.ty.clone();
1529
1530        let bool_expression = match &*expr_type.kind {
1531            TypeKind::Bool => resolved_expression,
1532            TypeKind::Optional(_) => {
1533                let bool = self.types().bool();
1534                self.create_expr(
1535                    ExpressionKind::CoerceOptionToBool(Box::new(resolved_expression)),
1536                    bool,
1537                    &expression.node,
1538                )
1539            }
1540            _ => self.create_err(ErrorKind::ExpectedBooleanExpression, &expression.node),
1541        };
1542
1543        BooleanExpression {
1544            expression: Box::from(bool_expression),
1545        }
1546    }
1547
1548    /// Check if an expression is a function call that returns an aggregate type
1549    fn is_aggregate_function_call(expression: &swamp_ast::Expression) -> bool {
1550        match &expression.kind {
1551            swamp_ast::ExpressionKind::PostfixChain(chain) => {
1552                if chain.postfixes.is_empty() {
1553                    return false;
1554                }
1555
1556                for postfix in &chain.postfixes {
1557                    if let swamp_ast::Postfix::FunctionCall(_, _, _) = postfix {
1558                        return true;
1559                    }
1560                }
1561                false
1562            }
1563            _ => false, // Other expressions (variables, literals, etc.) are not function calls
1564        }
1565    }
1566
1567    fn analyze_iterable(
1568        &mut self,
1569        mut_requested_for_value_variable: Option<swamp_ast::Node>,
1570        expression: &swamp_ast::Expression,
1571    ) -> Iterable {
1572        // Only set has_lvalue_target=false for function calls that return aggregates
1573        // Variables/parameters already have storage, so they should have has_lvalue_target=true
1574        let has_lvalue_target = !Self::is_aggregate_function_call(expression);
1575        let any_context = TypeContext::new_anything_argument(has_lvalue_target);
1576
1577        let resolved_expression = self.analyze_expression(expression, &any_context);
1578
1579        let resolved_type = &resolved_expression.ty.clone();
1580        let int_type = Some(self.types().int());
1581        let (key_type, value_type): (Option<TypeRef>, TypeRef) = match &*resolved_type.kind {
1582            TypeKind::String(_, char) => (int_type, char.clone()),
1583            TypeKind::SliceView(element_type) => (int_type, element_type.clone()),
1584            TypeKind::VecStorage(element_type, _fixed_size) => (int_type, element_type.clone()),
1585            TypeKind::SparseStorage(element_type, _fixed_size) => (int_type, element_type.clone()),
1586            TypeKind::StackStorage(element_type, _fixed_size) => (int_type, element_type.clone()),
1587            TypeKind::StackView(element_type) => (int_type, element_type.clone()),
1588            TypeKind::QueueStorage(element_type, _fixed_size) => (int_type, element_type.clone()),
1589            TypeKind::QueueView(element_type) => (int_type, element_type.clone()),
1590            TypeKind::DynamicLengthVecView(element_type) => (int_type, element_type.clone()),
1591            TypeKind::SparseView(element_type) => (int_type, element_type.clone()),
1592            TypeKind::DynamicLengthMapView(key_type, value_type)
1593            | TypeKind::MapStorage(key_type, value_type, _) => {
1594                (Some(key_type.clone()), value_type.clone())
1595            }
1596            TypeKind::Range(_) => (None, self.types().int()),
1597            _ => {
1598                error!(?resolved_type, "not an iterator");
1599                return Iterable {
1600                    key_type: None,
1601                    value_type: self.shared.state.types.unit(),
1602                    resolved_expression: Box::new(
1603                        self.create_err(ErrorKind::NotAnIterator, &expression.node),
1604                    ),
1605                };
1606            }
1607        };
1608
1609        if mut_requested_for_value_variable.is_some() {
1610            // we check if we can get to a lvalue, otherwise it is not mutable:
1611            let _resulting_location =
1612                self.analyze_to_location(expression, &any_context, LocationSide::Mutable);
1613            // Note: mutable references are now handled through SingleLocationExpression
1614            // The value_type stays the same, mutability is tracked separately
1615        }
1616
1617        Iterable {
1618            key_type,
1619            value_type,
1620            resolved_expression: Box::new(resolved_expression),
1621        }
1622    }
1623
1624    fn analyze_argument_expressions(
1625        &mut self,
1626        expected_type: Option<&TypeRef>,
1627        context: &TypeContext,
1628        ast_expressions: &[swamp_ast::Expression],
1629    ) -> Vec<Expression> {
1630        let mut resolved_expressions = Vec::new();
1631        // Function arguments should not have lvalue targets by default - they need proper storage allocation
1632        let argument_expressions_context = TypeContext::new_unsure_argument(expected_type, false);
1633
1634        for expression in ast_expressions {
1635            resolved_expressions
1636                .push(self.analyze_expression(expression, &argument_expressions_context));
1637        }
1638        resolved_expressions
1639    }
1640
1641    fn analyze_block(
1642        &mut self,
1643        _node: &swamp_ast::Node,
1644        context: &TypeContext,
1645        ast_expressions: &[swamp_ast::Expression],
1646    ) -> (Vec<Expression>, TypeRef) {
1647        if ast_expressions.is_empty() {
1648            return (vec![], self.shared.state.types.unit());
1649        }
1650
1651        self.push_block_scope("block");
1652
1653        let mut resolved_expressions = Vec::with_capacity(ast_expressions.len());
1654
1655        for expression in &ast_expressions[..ast_expressions.len() - 1] {
1656            let unit_type = self.shared.state.types.unit();
1657            let stmt_context =
1658                context.with_expected_type(Some(&unit_type), context.has_lvalue_target);
1659            let expr = self.analyze_expression(expression, &stmt_context);
1660
1661            resolved_expressions.push(expr);
1662        }
1663
1664        // Process the last expression - it determines the block's type
1665        let last_expr =
1666            self.analyze_expression(&ast_expressions[ast_expressions.len() - 1], context);
1667        let last_type = last_expr.ty.clone();
1668        resolved_expressions.push(last_expr);
1669
1670        self.pop_block_scope("block");
1671
1672        (resolved_expressions, last_type)
1673    }
1674
1675    fn analyze_interpolated_string_lowering(
1676        &mut self,
1677        node: &swamp_ast::Node,
1678        string_parts: &[swamp_ast::StringPart],
1679    ) -> Expression {
1680        let mut last_expression: Option<Expression> = None;
1681        for part in string_parts {
1682            let created_expression = match part {
1683                swamp_ast::StringPart::Literal(string_node, processed_string) => {
1684                    let string_literal =
1685                        ExpressionKind::StringLiteral(processed_string.to_string());
1686                    let basic_literal = string_literal;
1687                    let string_type = self.shared.state.types.string();
1688                    self.create_expr(basic_literal, string_type, string_node)
1689                }
1690                swamp_ast::StringPart::Interpolation(expression, format_specifier) => {
1691                    let any_context = TypeContext::new_anything_argument(false); // String interpolation context has no lvalue target for storage
1692
1693                    let expr = self.analyze_expression(expression, &any_context);
1694
1695                    let tk = (*expr.ty.kind).clone();
1696
1697                    let maybe_to_string = self
1698                        .shared
1699                        .state
1700                        .associated_impls
1701                        .get_internal_member_function(&expr.ty, "to_string");
1702
1703                    if matches!(tk, TypeKind::String { .. }) {
1704                        expr
1705                    } else {
1706                        let underlying = expr.ty.clone();
1707
1708                        // Check if the expression needs storage validation before proceeding
1709                        if self.needs_storage_error(&expr, true, &any_context, &expression.node) {
1710                            return self.create_err(ErrorKind::NeedStorage, &expression.node);
1711                        }
1712
1713                        let call_expr_kind = if maybe_to_string.is_none() {
1714                            let string_type = self.types().string();
1715
1716                            ExpressionKind::StringLiteral(format!("missing {string_type}"))
1717                            /* TODO:
1718
1719                                       return self.create_err(
1720                                           ErrorKind::MissingToString(string_type),
1721                                           &expression.node,
1722                                       );
1723
1724                            */
1725                        } else {
1726                            let expr_as_param = ArgumentExpression::Expression(expr);
1727                            self.create_static_member_call(
1728                                "to_string",
1729                                &[expr_as_param.clone()],
1730                                &expression.node,
1731                                &underlying,
1732                            )
1733                        };
1734
1735                        /*
1736                        TODO: SUPPORT FORMAT SPEC
1737                        let resolved_format_specifier =
1738                            self.analyze_format_specifier(Option::from(format_specifier));
1739
1740                         */
1741
1742                        let string_type = self.shared.state.types.string();
1743                        self.create_expr(call_expr_kind, string_type, &expression.node)
1744                    }
1745                }
1746            };
1747
1748            let x_last_expr = if let Some(last_expr) = last_expression.clone() {
1749                let op_kind = BinaryOperatorKind::Add;
1750                let node = created_expression.node.clone();
1751                let op = BinaryOperator {
1752                    left: Box::new(last_expr),
1753                    right: Box::new(created_expression),
1754                    kind: op_kind,
1755                    node: node.clone(),
1756                };
1757
1758                let string_type = self.shared.state.types.string();
1759                create_expr_resolved(ExpressionKind::BinaryOp(op), string_type, &node)
1760            } else {
1761                created_expression
1762            };
1763
1764            last_expression = Some(x_last_expr);
1765        }
1766
1767        // if we have no last_expression, then it means the whole
1768        // interpolation was completely was empty (`''`)
1769        if let Some(last) = last_expression {
1770            last
1771        } else {
1772            let string_type = self.shared.state.types.string();
1773            self.create_expr(
1774                ExpressionKind::StringLiteral(String::new()),
1775                string_type,
1776                node,
1777            )
1778        }
1779    }
1780
1781    pub(crate) fn analyze_identifier(
1782        &mut self,
1783        qualified_func_name: &swamp_ast::QualifiedIdentifier,
1784    ) -> Expression {
1785        // Must check variable first, since that is more intuitive for the user.
1786        // local variables before other functions
1787        if qualified_func_name.module_path.is_none()
1788            && qualified_func_name.generic_params.is_empty()
1789        {
1790            if let Some(found_variable) = self.try_find_variable(&qualified_func_name.name) {
1791                return self.create_expr(
1792                    ExpressionKind::VariableAccess(found_variable.clone()),
1793                    found_variable.resolved_type.clone(),
1794                    &qualified_func_name.name,
1795                );
1796            }
1797        }
1798
1799        let text = self.get_text(&qualified_func_name.name);
1800        self.create_err(
1801            ErrorKind::UnknownIdentifier(text.to_string()),
1802            &qualified_func_name.name,
1803        )
1804    }
1805
1806    // The ast assumes it is something similar to a variable, but it can be a function reference as well.
1807    fn analyze_variable_reference(&mut self, var_node: &swamp_ast::Node) -> Expression {
1808        if let Some(found_variable) = self.try_find_variable(var_node) {
1809            return self.create_expr(
1810                ExpressionKind::VariableAccess(found_variable.clone()),
1811                found_variable.resolved_type.clone(),
1812                var_node,
1813            );
1814        }
1815        let text = self.get_text(var_node);
1816        self.create_err(ErrorKind::UnknownIdentifier(text.to_string()), var_node)
1817    }
1818    fn analyze_slice_pair_literal(
1819        &mut self,
1820        node: &swamp_ast::Node,
1821        entries: &[(swamp_ast::Expression, swamp_ast::Expression)],
1822    ) -> (Vec<(Expression, Expression)>, TypeRef, TypeRef) {
1823        if entries.is_empty() {
1824            return (
1825                vec![],
1826                self.shared.state.types.unit(),
1827                self.shared.state.types.unit(),
1828            );
1829        }
1830
1831        // Resolve first entry to determine map types
1832        let (first_key, first_value) = &entries[0];
1833        let anything_context = TypeContext::new_anything_argument(true);
1834        let resolved_first_key = self.analyze_expression(first_key, &anything_context);
1835        let resolved_first_value = self.analyze_expression(first_value, &anything_context);
1836        let key_type = resolved_first_key.ty.clone();
1837        let value_type = resolved_first_value.ty.clone();
1838
1839        let key_context = TypeContext::new_argument(&key_type, true);
1840        let value_context = TypeContext::new_argument(&value_type, true);
1841
1842        // Check all entries match the types
1843        let mut resolved_entries = Vec::new();
1844        resolved_entries.push((resolved_first_key, resolved_first_value));
1845
1846        for (key, value) in entries.iter().skip(1) {
1847            let resolved_key = self.analyze_expression(key, &key_context);
1848            let resolved_value = self.analyze_expression(value, &value_context);
1849
1850            if !self
1851                .shared
1852                .state
1853                .types
1854                .compatible_with(&resolved_key.ty, &key_type)
1855            {
1856                return (
1857                    vec![],
1858                    self.shared.state.types.unit(),
1859                    self.shared.state.types.unit(),
1860                );
1861            }
1862
1863            if !self
1864                .shared
1865                .state
1866                .types
1867                .compatible_with(&resolved_value.ty, &value_type)
1868            {
1869                return (
1870                    vec![],
1871                    self.shared.state.types.unit(),
1872                    self.shared.state.types.unit(),
1873                );
1874            }
1875
1876            resolved_entries.push((resolved_key, resolved_value));
1877        }
1878
1879        (resolved_entries, key_type, value_type)
1880    }
1881
1882    fn analyze_internal_initializer_pair_list(
1883        &mut self,
1884        node: &swamp_ast::Node,
1885        items: &[(swamp_ast::Expression, swamp_ast::Expression)],
1886        context: &TypeContext,
1887    ) -> (TypeRef, Vec<(Expression, Expression)>) {
1888        let (collection_type, key_type, value_type) = if let Some(expected_type) =
1889            context.expected_type
1890        {
1891            match &*expected_type.kind {
1892                TypeKind::MapStorage(key, value, capacity) => {
1893                    if items.len() > *capacity {
1894                        self.add_err(
1895                            ErrorKind::TooManyInitializerListElementsForStorage {
1896                                capacity: *capacity,
1897                            },
1898                            node,
1899                        );
1900                        return (self.types().unit(), vec![]);
1901                    }
1902                    (expected_type.clone(), key.clone(), value.clone())
1903                }
1904                TypeKind::DynamicLengthMapView(key, value) => {
1905                    (expected_type.clone(), key.clone(), value.clone())
1906                }
1907                _ => {
1908                    self.add_err(ErrorKind::ExpectedSlice, node);
1909                    return (self.types().unit(), vec![]);
1910                }
1911            }
1912        } else if items.is_empty() {
1913            self.add_err(ErrorKind::NoInferredTypeForEmptyInitializer, node);
1914            return (self.types().unit(), vec![]);
1915        } else {
1916            // Try to detect, by checking the first
1917            let maybe_key_context = TypeContext::new_anything_argument(true);
1918
1919            let first_key_expression = self.analyze_expression(&items[0].0, &maybe_key_context);
1920
1921            let maybe_value_context = TypeContext::new_anything_argument(true);
1922            let first_value_expression = self.analyze_expression(&items[0].1, &maybe_value_context);
1923
1924            let required_key_type = first_key_expression.ty;
1925            let required_value_type = first_value_expression.ty;
1926
1927            let inferred_type =
1928                self.types()
1929                    .map_storage(&required_key_type, &required_value_type, items.len());
1930
1931            (inferred_type, required_key_type, required_value_type)
1932        };
1933
1934        assert!(!matches!(*key_type.kind, TypeKind::Unit));
1935        assert!(!matches!(*value_type.kind, TypeKind::Unit));
1936
1937        let required_key_context = TypeContext::new_argument(&key_type, true);
1938        let required_value_context = TypeContext::new_argument(&value_type, true);
1939
1940        let mut resolved_items = Vec::new();
1941
1942        for (key_expr, value_expr) in items {
1943            let analyzed_key_expr = self.analyze_expression(key_expr, &required_key_context);
1944            let analyzed_value_expr = self.analyze_expression(value_expr, &required_value_context);
1945            resolved_items.push((analyzed_key_expr, analyzed_value_expr));
1946        }
1947
1948        (collection_type, resolved_items)
1949    }
1950
1951    fn analyze_internal_initializer_list(
1952        &mut self,
1953        node: &swamp_ast::Node,
1954        items: &[swamp_ast::Expression],
1955        context: &TypeContext,
1956    ) -> (TypeRef, Vec<Expression>) {
1957        let (collection_type, element_type) = if let Some(expected_type) = context.expected_type {
1958            match &*expected_type.kind {
1959                TypeKind::GridStorage(element_type, width, height) => {
1960                    let capacity = width * height;
1961                    if items.len() > capacity {
1962                        return (
1963                            self.types().unit(),
1964                            self.create_err_vec(
1965                                ErrorKind::TooManyInitializerListElementsForStorage { capacity },
1966                                node,
1967                            ),
1968                        );
1969                    }
1970                    (expected_type.clone(), element_type.clone())
1971                }
1972                TypeKind::StackStorage(element_type, capacity)
1973                | TypeKind::QueueStorage(element_type, capacity)
1974                | TypeKind::SparseStorage(element_type, capacity)
1975                | TypeKind::VecStorage(element_type, capacity) => {
1976                    if items.len() > *capacity {
1977                        return (
1978                            self.types().unit(),
1979                            self.create_err_vec(
1980                                ErrorKind::TooManyInitializerListElementsForStorage {
1981                                    capacity: *capacity,
1982                                },
1983                                node,
1984                            ),
1985                        );
1986                    }
1987                    (expected_type.clone(), element_type.clone())
1988                }
1989                TypeKind::QueueView(element_type)
1990                | TypeKind::SparseView(element_type)
1991                | TypeKind::StackView(element_type)
1992                | TypeKind::GridView(element_type)
1993                | TypeKind::DynamicLengthVecView(element_type) => {
1994                    (expected_type.clone(), element_type.clone())
1995                }
1996                TypeKind::FixedCapacityAndLengthArray(element_type, _size) => {
1997                    (expected_type.clone(), element_type.clone())
1998                }
1999                TypeKind::SliceView(element_type) => (expected_type.clone(), element_type.clone()),
2000                _ => {
2001                    return (
2002                        self.types().unit(),
2003                        self.create_err_vec(
2004                            ErrorKind::ExpectedInitializerTarget {
2005                                destination_type: expected_type.clone(),
2006                            },
2007                            node,
2008                        ),
2009                    );
2010                }
2011            }
2012        } else if items.is_empty() {
2013            return (
2014                self.types().unit(),
2015                self.create_err_vec(ErrorKind::NoInferredTypeForEmptyInitializer, node),
2016            );
2017        } else {
2018            // Try to detect, by checking the first
2019            let maybe_context = TypeContext::new_anything_argument(true);
2020            let first = self.analyze_expression(&items[0], &maybe_context);
2021            let required_type = first.ty;
2022            let inferred_vec_storage_type = self.types().vec_storage(&required_type, items.len());
2023            // Generate default functions for the inferred vec storage type
2024            let default_node = swamp_ast::Node::default();
2025            self.add_default_functions(&inferred_vec_storage_type, &default_node);
2026            (inferred_vec_storage_type, required_type)
2027        };
2028
2029        let required_context = TypeContext::new_argument(&element_type, true);
2030        let mut resolved_items = Vec::new();
2031        for item in items {
2032            let resolved_expr = self.analyze_expression(item, &required_context);
2033            resolved_items.push(resolved_expr);
2034        }
2035        (collection_type, resolved_items)
2036    }
2037
2038    fn push_block_scope(&mut self, debug_str: &str) {
2039        let register_watermark = self.scope.total_scopes.current_register;
2040
2041        self.scope.active_scope.block_scope_stack.push(BlockScope {
2042            mode: BlockScopeMode::Open,
2043            lookup: Default::default(),
2044            variables: SeqMap::default(),
2045            register_watermark,
2046        });
2047    }
2048
2049    fn push_lambda_scope(&mut self, debug_str: &str) {
2050        // Lambda scopes are virtual and completely transparent to register allocation
2051        // They don't save any watermark and don't affect register allocation
2052        self.scope.active_scope.block_scope_stack.push(BlockScope {
2053            mode: BlockScopeMode::Lambda,
2054            lookup: SeqMap::default(),
2055            variables: SeqMap::default(),
2056            register_watermark: 0, // Not used for lambda scopes
2057        });
2058    }
2059
2060    fn pop_block_scope(&mut self, debug_str: &str) {
2061        self.pop_any_block_scope();
2062    }
2063
2064    fn push_closed_block_scope(&mut self) {
2065        let register_watermark = self.scope.total_scopes.current_register;
2066        self.scope.active_scope.block_scope_stack.push(BlockScope {
2067            mode: BlockScopeMode::Closed,
2068            lookup: Default::default(),
2069            variables: SeqMap::default(),
2070            register_watermark,
2071        });
2072    }
2073
2074    fn pop_closed_block_scope(&mut self) {
2075        //self.scope.active_scope.block_scope_stack.pop();
2076        self.pop_any_block_scope();
2077    }
2078
2079    fn pop_any_block_scope(&mut self) {
2080        let scope = self.scope.active_scope.block_scope_stack.pop().unwrap();
2081
2082        // Record the highest watermark (greatest depth of virtual registers)
2083        self.scope.total_scopes.highest_virtual_register = self.scope.total_scopes.current_register;
2084
2085        // Check if we're inside a lambda scope - if so, don't restore register counter
2086        let is_inside_lambda = self
2087            .scope
2088            .active_scope
2089            .block_scope_stack
2090            .iter()
2091            .any(|s| matches!(s.mode, BlockScopeMode::Lambda));
2092
2093        if matches!(scope.mode, BlockScopeMode::Lambda) {
2094            // lambda scope - completely transparent, no register changes
2095        } else if is_inside_lambda {
2096            // block scope inside lambda - virtual, no register restoration
2097        } else {
2098            // Regular scopes restore their watermark to free up registers
2099            self.scope.total_scopes.current_register = scope.register_watermark;
2100        }
2101    }
2102
2103    fn analyze_match(
2104        &mut self,
2105        scrutinee: &swamp_ast::Expression,
2106        default_context: &TypeContext,
2107        arms: &Vec<swamp_ast::MatchArm>,
2108    ) -> (Match, TypeRef) {
2109        let mut known_type = default_context.expected_type.cloned();
2110        let own_context = default_context.clone();
2111        // Analyze the scrutinee with no specific expected type
2112        let scrutinee_context = TypeContext::new_anything_argument(true); // we just using the pointer, so pretend that it is a target
2113        let resolved_scrutinee = self.analyze_expression(scrutinee, &scrutinee_context);
2114        let scrutinee_type = resolved_scrutinee.ty.clone();
2115
2116        let mut resolved_arms = Vec::with_capacity(arms.len());
2117
2118        // Ensure we have at least one arm
2119        if arms.is_empty() {
2120            let err_match = Match {
2121                expression: Box::new(
2122                    self.create_err(ErrorKind::MatchMustHaveAtLeastOneArm, &scrutinee.node),
2123                ),
2124                arms: resolved_arms,
2125            };
2126            return (err_match, self.types().unit());
2127        }
2128
2129        for arm in arms {
2130            let (resolved_arm, _anyone_wants_mutable) = self.analyze_arm(
2131                arm,
2132                &resolved_scrutinee,
2133                &own_context.with_expected_type(known_type.as_ref(), false),
2134                &scrutinee_type,
2135            );
2136
2137            if known_type.is_none() {
2138                known_type = Some(resolved_arm.expression.ty.clone());
2139            }
2140            resolved_arms.push(resolved_arm);
2141        }
2142
2143        if let Some(encountered_type) = known_type {
2144            (
2145                Match {
2146                    expression: Box::new(resolved_scrutinee),
2147                    arms: resolved_arms,
2148                },
2149                encountered_type,
2150            )
2151        } else {
2152            let err_expr = self.create_err(ErrorKind::MatchArmsMustHaveTypes, &scrutinee.node);
2153
2154            (
2155                Match {
2156                    expression: Box::new(err_expr),
2157                    arms: resolved_arms.clone(),
2158                },
2159                self.types().unit(),
2160            )
2161        }
2162    }
2163
2164    fn analyze_arm(
2165        &mut self,
2166        arm: &swamp_ast::MatchArm,
2167        _expression: &Expression,
2168        type_context: &TypeContext,
2169        expected_condition_type: &TypeRef,
2170    ) -> (MatchArm, bool) {
2171        let (resolved_pattern, scope_was_pushed, anyone_wants_mutable) =
2172            self.analyze_pattern(&arm.pattern, expected_condition_type);
2173
2174        let resolved_expression = self.analyze_expression(&arm.expression, type_context);
2175        if scope_was_pushed {
2176            self.pop_block_scope("analyze_arm");
2177        }
2178
2179        let resolved_type = resolved_expression.ty.clone();
2180
2181        (
2182            MatchArm {
2183                pattern: resolved_pattern,
2184                expression: Box::from(resolved_expression),
2185                expression_type: resolved_type,
2186            },
2187            anyone_wants_mutable,
2188        )
2189    }
2190
2191    fn str_to_int(text: &str) -> Result<i32, ParseIntError> {
2192        let text = text.replace('_', "");
2193        text.strip_prefix("0x").map_or_else(
2194            || {
2195                text.strip_prefix("-0x").map_or_else(
2196                    || text.parse::<i32>(),
2197                    |rest| i32::from_str_radix(rest, 16).map(|x| -x),
2198                )
2199            },
2200            |rest| i32::from_str_radix(rest, 16),
2201        )
2202    }
2203
2204    fn str_to_unsigned_int(text: &str) -> Result<u32, ParseIntError> {
2205        let text = text.replace('_', "");
2206        text.strip_prefix("0x")
2207            .map_or_else(|| text.parse::<u32>(), |rest| u32::from_str_radix(rest, 16))
2208    }
2209
2210    fn str_to_float(text: &str) -> Result<f32, ParseFloatError> {
2211        text.parse::<f32>()
2212    }
2213
2214    fn str_to_bool(text: &str) -> Result<bool, ParseBoolError> {
2215        bool::from_str(text)
2216    }
2217
2218    fn analyze_pattern_literal(
2219        &mut self,
2220        node: &swamp_ast::Node,
2221        ast_literal: &swamp_ast::LiteralKind,
2222        expected_condition_type: &TypeRef,
2223    ) -> NormalPattern {
2224        let required_condition_type_context =
2225            TypeContext::new_argument(expected_condition_type, false);
2226        let literal = self.analyze_literal(node, ast_literal, &required_condition_type_context);
2227
2228        if !self
2229            .types()
2230            .compatible_with(&literal.ty, expected_condition_type)
2231        {
2232            return NormalPattern::Literal(self.create_err(
2233                ErrorKind::IncompatibleTypes {
2234                    expected: expected_condition_type.clone(),
2235                    found: literal.ty,
2236                },
2237                node,
2238            ));
2239        }
2240
2241        NormalPattern::Literal(literal)
2242    }
2243
2244    const fn to_node(&self, node: &swamp_ast::Node) -> Node {
2245        Node {
2246            span: Span {
2247                file_id: self.shared.file_id,
2248                offset: node.span.offset,
2249                length: node.span.length,
2250            },
2251        }
2252    }
2253
2254    fn get_module_path(&self, module_path: Option<&swamp_ast::ModulePath>) -> Vec<String> {
2255        module_path.as_ref().map_or_else(Vec::new, |found| {
2256            let mut strings = Vec::new();
2257            for path_item in &found.0 {
2258                strings.push(self.get_text(path_item).to_string());
2259            }
2260            strings
2261        })
2262    }
2263
2264    fn get_enum_variant_type(
2265        &mut self,
2266        qualified_type_identifier: &swamp_ast::QualifiedTypeIdentifier,
2267        variant_name: &str,
2268    ) -> EnumVariantType {
2269        let Some((symbol_table, enum_name)) =
2270            self.get_symbol_table_and_name(qualified_type_identifier)
2271        else {
2272            self.add_err(
2273                ErrorKind::UnknownEnumVariantType,
2274                &qualified_type_identifier.name.0,
2275            );
2276            return EnumVariantType {
2277                common: EnumVariantCommon {
2278                    name: Default::default(),
2279                    assigned_name: String::new(),
2280                    container_index: 0,
2281                },
2282                payload_type: self.types().unit(),
2283            };
2284        };
2285
2286        if let Some(enum_name) = symbol_table.get_enum_variant_type(&enum_name, variant_name) {
2287            enum_name
2288        } else {
2289            self.add_err(
2290                ErrorKind::UnknownEnumVariantType,
2291                &qualified_type_identifier.name.0,
2292            );
2293            EnumVariantType {
2294                common: EnumVariantCommon {
2295                    name: Default::default(),
2296                    assigned_name: String::new(),
2297                    container_index: 0,
2298                },
2299                payload_type: self.types().unit(),
2300            }
2301        }
2302    }
2303
2304    pub(crate) fn get_symbol_table_and_name(
2305        &self,
2306        type_identifier: &swamp_ast::QualifiedTypeIdentifier,
2307    ) -> Option<(&SymbolTable, String)> {
2308        let path = self.get_module_path(type_identifier.module_path.as_ref());
2309        let name = self.get_text(&type_identifier.name.0).to_string();
2310
2311        if let Some(found) = self.shared.get_symbol_table(&path) {
2312            Some((found, name))
2313        } else {
2314            None
2315        }
2316    }
2317
2318    const fn analyze_compound_operator(
2319        &self,
2320        ast_operator: &swamp_ast::CompoundOperator,
2321    ) -> CompoundOperator {
2322        let resolved_node = self.to_node(&ast_operator.node);
2323        let resolved_kind = match ast_operator.kind {
2324            swamp_ast::CompoundOperatorKind::Add => CompoundOperatorKind::Add,
2325            swamp_ast::CompoundOperatorKind::Sub => CompoundOperatorKind::Sub,
2326            swamp_ast::CompoundOperatorKind::Mul => CompoundOperatorKind::Mul,
2327            swamp_ast::CompoundOperatorKind::Div => CompoundOperatorKind::Div,
2328            swamp_ast::CompoundOperatorKind::Modulo => CompoundOperatorKind::Modulo,
2329        };
2330
2331        CompoundOperator {
2332            node: resolved_node,
2333            kind: resolved_kind,
2334        }
2335    }
2336
2337    const fn to_node_option(&self, maybe_node: Option<&swamp_ast::Node>) -> Option<Node> {
2338        match maybe_node {
2339            None => None,
2340            Some(node) => Some(self.to_node(node)),
2341        }
2342    }
2343
2344    const fn analyze_format_specifier(
2345        &self,
2346        ast_format_specifier: Option<&swamp_ast::FormatSpecifier>,
2347    ) -> Option<FormatSpecifier> {
2348        let f = match ast_format_specifier {
2349            None => return None,
2350            Some(ast_format) => match ast_format {
2351                swamp_ast::FormatSpecifier::LowerHex(node) => FormatSpecifier {
2352                    node: self.to_node(node),
2353                    kind: FormatSpecifierKind::LowerHex,
2354                },
2355                swamp_ast::FormatSpecifier::UpperHex(node) => FormatSpecifier {
2356                    node: self.to_node(node),
2357                    kind: FormatSpecifierKind::UpperHex,
2358                },
2359                swamp_ast::FormatSpecifier::Binary(node) => FormatSpecifier {
2360                    node: self.to_node(node),
2361                    kind: FormatSpecifierKind::Binary,
2362                },
2363                swamp_ast::FormatSpecifier::Float(node) => FormatSpecifier {
2364                    node: self.to_node(node),
2365                    kind: FormatSpecifierKind::Float,
2366                },
2367                swamp_ast::FormatSpecifier::Precision(value, node, x) => {
2368                    let (precision_type, precision_node) = match x {
2369                        swamp_ast::PrecisionType::Float(node) => {
2370                            (PrecisionType::Float, self.to_node(node))
2371                        }
2372                        swamp_ast::PrecisionType::String(node) => {
2373                            (PrecisionType::String, self.to_node(node))
2374                        }
2375                    };
2376                    FormatSpecifier {
2377                        node: self.to_node(node),
2378                        kind: FormatSpecifierKind::Precision(
2379                            *value,
2380                            precision_node,
2381                            precision_type,
2382                        ),
2383                    }
2384                }
2385            },
2386        };
2387
2388        Some(f)
2389    }
2390
2391    fn analyze_with_expr(
2392        &mut self,
2393        context: &TypeContext,
2394        variables: &[swamp_ast::VariableBinding],
2395        expression: &swamp_ast::Expression,
2396    ) -> Expression {
2397        let mut variable_expressions = Vec::new();
2398
2399        for variable in variables {
2400            let any_context = TypeContext::new_anything_argument(false);
2401            let must_have_expression = if let Some(x) = &variable.expression {
2402                x
2403            } else {
2404                &swamp_ast::Expression {
2405                    kind: swamp_ast::ExpressionKind::VariableReference(variable.variable.clone()),
2406                    node: variable.variable.name.clone(),
2407                }
2408            };
2409
2410            // Determine the correct LocationSide based on the variable binding type
2411            let location_side = if variable.variable.is_mutable.is_some() {
2412                // For mutable variables in with statements, we need to check if this is an lvalue binding
2413                if let Some(expr) = &variable.expression {
2414                    // Use analyze_maybe_ref_expression to properly detect mutable references
2415                    let maybe_ref = self.analyze_maybe_ref_expression(expr);
2416                    if maybe_ref.has_borrow_mutable_reference.is_some() {
2417                        LocationSide::Mutable
2418                    } else {
2419                        LocationSide::Rhs
2420                    }
2421                } else {
2422                    // For cases like `with mut x` (no expression), it's an alias
2423                    LocationSide::Rhs
2424                }
2425            } else {
2426                // For immutable variables, always use Rhs
2427                LocationSide::Rhs
2428            };
2429
2430            let var = self.analyze_mut_or_immutable_expression(
2431                must_have_expression,
2432                &any_context,
2433                location_side,
2434            );
2435
2436            variable_expressions.push(var);
2437        }
2438
2439        self.push_closed_block_scope();
2440        let mut expressions = Vec::new();
2441        for (variable_binding, resolved_expression) in variables.iter().zip(variable_expressions) {
2442            let initialize_variable_expression = self
2443                .create_variable_binding_for_with(&variable_binding.variable, resolved_expression);
2444
2445            // Always add the expression to ensure proper initialization/binding
2446            // Even for aliases (VariableAccess), we need the expression in the block
2447            // to establish the proper scope and binding
2448            expressions.push(initialize_variable_expression);
2449        }
2450
2451        let resolved_expression = self.analyze_expression(expression, context);
2452        // with statements are for side effects only, so they always return Unit type
2453        let block_type = self.types().unit();
2454        expressions.push(resolved_expression);
2455
2456        let block_expression_kind = ExpressionKind::Block(expressions);
2457        self.pop_closed_block_scope();
2458
2459        self.create_expr(block_expression_kind, block_type, &expression.node)
2460    }
2461
2462    fn analyze_when_expr(
2463        &mut self,
2464        context: &TypeContext,
2465        variables: &[swamp_ast::VariableBinding],
2466        true_expr: &swamp_ast::Expression,
2467        else_expr: Option<&swamp_ast::Expression>,
2468    ) -> Expression {
2469        // Since we are making new variable bindings, we have to push a scope for them
2470        self.push_block_scope("when");
2471        let mut bindings = Vec::new();
2472        for variable_binding in variables {
2473            let mut_expr = if let Some(found_expr) = &variable_binding.expression {
2474                let any_context = TypeContext::new_anything_argument(true); // we are not just having an alias binding to another value, so we can think of it having a target
2475                self.analyze_mut_or_immutable_expression(
2476                    found_expr,
2477                    &any_context,
2478                    LocationSide::Rhs,
2479                )
2480                    .expect_immutable()
2481                    .unwrap()
2482            } else {
2483                let same_var = self.find_variable(&variable_binding.variable);
2484
2485                // For when expressions, we always want to extract the value from the optional,
2486                // not create a mutable reference to the original variable
2487                let generated_expr_kind = ExpressionKind::VariableAccess(same_var.clone());
2488                self.create_expr(
2489                    generated_expr_kind,
2490                    same_var.resolved_type.clone(),
2491                    &variable_binding.variable.name,
2492                )
2493            };
2494
2495            let tk = &mut_expr.ty.kind;
2496
2497            if let TypeKind::Optional(found_ty) = &**tk {
2498                let variable_ref = self.create_variable(&variable_binding.variable, found_ty);
2499
2500                let binding = WhenBinding {
2501                    variable: variable_ref,
2502                    expr: mut_expr,
2503                };
2504                bindings.push(binding);
2505            } else {
2506                return self.create_err(ErrorKind::ExpectedOptional, &true_expr.node);
2507            }
2508        }
2509
2510        let resolved_true = self.analyze_expression(true_expr, context);
2511        let block_type = resolved_true.ty.clone();
2512
2513        self.pop_block_scope("when");
2514
2515        let maybe_resolved_else = if let Some(found_else) = else_expr {
2516            let block_type_for_true_context = context.we_know_expected_type(&block_type, false);
2517            Some(Box::new(self.analyze_expression(
2518                found_else,
2519                &block_type_for_true_context,
2520            )))
2521        } else {
2522            None
2523        };
2524
2525        let when_kind =
2526            ExpressionKind::When(bindings, Box::from(resolved_true), maybe_resolved_else);
2527
2528        self.create_expr(when_kind, block_type, &true_expr.node)
2529    }
2530
2531    fn analyze_guard(
2532        &mut self,
2533        node: &swamp_ast::Node,
2534        context: &TypeContext,
2535        guard_expressions: &Vec<swamp_ast::GuardExpr>,
2536    ) -> Expression {
2537        let mut guards = Vec::new();
2538        let mut found_wildcard = None;
2539        let mut detected_type = context.expected_type.cloned();
2540
2541        for guard in guard_expressions {
2542            let resolved_condition = match &guard.clause {
2543                swamp_ast::GuardClause::Wildcard(x) => {
2544                    if found_wildcard.is_some() {
2545                        return self.create_err(ErrorKind::GuardCanNotHaveMultipleWildcards, node);
2546                    }
2547                    found_wildcard = Some(x);
2548                    None
2549                }
2550                swamp_ast::GuardClause::Expression(clause_expr) => {
2551                    if found_wildcard.is_some() {
2552                        return self.create_err(ErrorKind::WildcardMustBeLastInGuard, node);
2553                    }
2554                    Some(self.analyze_bool_argument_expression(clause_expr))
2555                }
2556            };
2557
2558            let resolved_result = self.analyze_expression(
2559                &guard.result,
2560                &context.with_expected_type(detected_type.as_ref(), false),
2561            );
2562            let ty = resolved_result.ty.clone();
2563            if detected_type.is_none() {
2564                detected_type = Some(ty.clone());
2565            }
2566
2567            guards.push(Guard {
2568                condition: resolved_condition,
2569                result: resolved_result,
2570            });
2571        }
2572
2573        if found_wildcard.is_none() {
2574            return self.create_err(ErrorKind::GuardMustHaveWildcard, node);
2575        }
2576
2577        let kind = ExpressionKind::Guard(guards);
2578
2579        if let Some(found_expecting_type) = detected_type {
2580            self.create_expr(kind, found_expecting_type, node)
2581        } else {
2582            self.create_err(ErrorKind::GuardHasNoType, node)
2583        }
2584    }
2585
2586    fn analyze_lambda(
2587        &mut self,
2588        node: &swamp_ast::Node,
2589        variables: &[swamp_ast::Variable],
2590        ast_expr: &swamp_ast::Expression,
2591        context: &TypeContext,
2592    ) -> Expression {
2593        let TypeKind::Function(signature) = &*context.expected_type.unwrap().kind else {
2594            return self.create_err(ErrorKind::ExpectedLambda, node);
2595        };
2596
2597        let return_block_type = TypeContext::new_argument(&signature.return_type, false);
2598
2599        // Create a lambda scope for proper variable scoping and shadowing
2600        // But the register allocation will "continue" from parent scope (no decrement on pop)
2601        self.push_lambda_scope("lambda");
2602
2603        let arity_required = signature.parameters.len();
2604        let variable_types_to_create = if variables.len() == arity_required {
2605            &signature.parameters
2606        } else if variables.len() + 1 == arity_required {
2607            &signature.parameters[1..].to_vec()
2608        } else {
2609            return self.create_err(ErrorKind::WrongNumberOfArguments(0, 0), node);
2610        };
2611
2612        let mut resolved_variables = Vec::new();
2613        for (variable, variable_type) in variables.iter().zip(variable_types_to_create) {
2614            let variable_ref = self.create_local_variable(
2615                &variable.name,
2616                variable.is_mutable.as_ref(),
2617                &variable_type.resolved_type,
2618                false,
2619            );
2620            resolved_variables.push(variable_ref);
2621        }
2622
2623        // Analyze the lambda body expression directly without creating additional block scopes
2624        // This ensures lambda variables are allocated in the lambda scope, not inner scopes
2625        let analyzed_expression = self.analyze_expression(ast_expr, &return_block_type);
2626
2627        self.pop_block_scope("lambda");
2628
2629        let function_type = self.types().function(signature.clone());
2630        self.create_expr(
2631            ExpressionKind::Lambda(resolved_variables, Box::new(analyzed_expression)),
2632            function_type,
2633            node,
2634        )
2635    }
2636
2637    #[must_use]
2638    pub fn chain_is_owned_result(
2639        start_of_chain: &StartOfChain,
2640        chains: &Vec<Postfix>,
2641    ) -> (bool, bool) {
2642        let mut is_owned_result = matches!(start_of_chain.kind, StartOfChainKind::Expression(_));
2643        let mut is_mutable = if let StartOfChainKind::Variable(var) = &start_of_chain.kind {
2644            var.is_mutable()
2645        } else {
2646            false
2647        };
2648
2649        for chain in chains {
2650            match chain.kind {
2651                PostfixKind::StructField(_, _) => {
2652                    is_owned_result = false;
2653                }
2654                PostfixKind::SliceViewSubscript(_, _) => {
2655                    is_owned_result = false;
2656                }
2657                PostfixKind::MemberCall(_, _) => {
2658                    is_owned_result = true;
2659                    is_mutable = false;
2660                }
2661                PostfixKind::OptionalChainingOperator => {
2662                    is_owned_result = true;
2663                    is_mutable = false;
2664                }
2665                PostfixKind::NoneCoalescingOperator(_) => {
2666                    is_owned_result = true;
2667                    is_mutable = false;
2668                }
2669                PostfixKind::VecSubscript(_, _) => {}
2670                PostfixKind::SparseSubscript(_, _) => {}
2671                PostfixKind::GridSubscript(_, _, _) => {}
2672                PostfixKind::MapSubscript(_, _) => {}
2673            }
2674        }
2675
2676        (is_owned_result, is_mutable)
2677    }
2678
2679    pub fn check_assignment_mode(
2680        &mut self,
2681        lhs_is_mutable: bool,
2682        source_expression: &Expression,
2683        ty: &TypeRef,
2684    ) -> AssignmentMode {
2685        if matches!(
2686            &source_expression.kind,
2687            _ | ExpressionKind::IntrinsicCallEx(_, _)
2688        ) {
2689            return AssignmentMode::OwnedValue;
2690        }
2691
2692        /* TODO:
2693        if ty.is_direct() {
2694            return AssignmentMode::OwnedValue;
2695        }
2696
2697         */
2698
2699        if let ExpressionKind::PostfixChain(start_chain, postfix) = &source_expression.kind {
2700            let (chain_is_owned, chain_is_mutable) =
2701                Self::chain_is_owned_result(start_chain, postfix);
2702            if lhs_is_mutable {
2703                return if chain_is_mutable {
2704                    AssignmentMode::CopyBlittable
2705                } else if lhs_is_mutable {
2706                    if chain_is_owned {
2707                        AssignmentMode::OwnedValue
2708                    } else {
2709                        AssignmentMode::CopyBlittable
2710                    }
2711                } else {
2712                    AssignmentMode::CopySharedPtr
2713                };
2714            }
2715            // if not mutable, it is always ok
2716        }
2717
2718        AssignmentMode::CopyBlittable
2719    }
2720
2721    pub const fn check_mutable_assignment(&mut self, assignment_mode: AssignmentMode, node: &Node) {}
2722
2723    pub const fn check_mutable_variable_assignment(
2724        &mut self,
2725        source_expression: &swamp_ast::Expression,
2726        ty: &TypeRef,
2727        variable: &swamp_ast::Variable,
2728    ) {
2729        //let is_allowed_to_assign = Self::check_mutable_assignment_is_valid(ty);
2730        //if !is_allowed_to_assign {
2731        //  error!(?ty, "variable is wrong");
2732        //return Err(self.create_err(ErrorKind::ArgumentIsNotMutable, &variable.name));
2733        //}
2734    }
2735
2736    /// # Errors
2737    ///
2738    pub fn analyze_variable_assignment(
2739        &mut self,
2740        variable: &swamp_ast::Variable,
2741        source_expression: &swamp_ast::Expression,
2742    ) -> Expression {
2743        let maybe_found_variable = self.try_find_variable(&variable.name);
2744
2745        let required_type = maybe_found_variable
2746            .as_ref()
2747            .map(|found_variable| found_variable.resolved_type.clone());
2748
2749        let source_expr = if let Some(target_type) = &required_type {
2750            self.analyze_expression_for_assignment_with_target_type(target_type, source_expression)
2751        } else {
2752            let any_type_context = TypeContext::new_anything_argument(true);
2753            self.analyze_expression(source_expression, &any_type_context)
2754        };
2755
2756        // Check if the variable type (target type) can be stored in a variable
2757        // Skip this check for parameters since they already have allocated storage
2758        let target_type = if let Some(found_var) = &maybe_found_variable {
2759            &found_var.resolved_type
2760        } else {
2761            &source_expr.ty
2762        };
2763
2764        // Only check blittable for local variables, not parameters
2765        let should_check_blittable = if let Some(found_var) = &maybe_found_variable {
2766            !matches!(found_var.variable_type, VariableType::Parameter)
2767        } else {
2768            true // New variable definitions need to be blittable
2769        };
2770
2771        if should_check_blittable && !target_type.is_blittable() {
2772            let debug_text = self.get_text(&variable.name);
2773            if !debug_text.starts_with('_') {
2774                return self.create_err(
2775                    ErrorKind::VariableTypeMustBeBlittable(target_type.clone()),
2776                    &variable.name,
2777                );
2778            }
2779        }
2780
2781        let kind: ExpressionKind = if let Some(found_var) = maybe_found_variable {
2782            if !found_var.is_mutable() {
2783                return self.create_err(ErrorKind::VariableIsNotMutable, &variable.name);
2784            }
2785            if !self
2786                .types()
2787                .compatible_with(&found_var.resolved_type, &source_expr.ty)
2788            {
2789                return self.create_err(
2790                    ErrorKind::IncompatibleTypes {
2791                        expected: source_expr.ty,
2792                        found: found_var.resolved_type.clone(),
2793                    },
2794                    &variable.name,
2795                );
2796            }
2797            self.check_mutable_variable_assignment(source_expression, &source_expr.ty, variable);
2798            ExpressionKind::VariableReassignment(found_var, Box::from(source_expr))
2799        } else {
2800            if !source_expr.ty.is_blittable() {
2801                let text = self.get_text(&variable.name);
2802                error!(?text, ?required_type, ?source_expr, "variable is wrong");
2803            }
2804
2805            // If it is mutable, we might need to clone the source
2806            // so make some extra verification
2807            if variable.is_mutable.is_some() {
2808                self.check_mutable_variable_assignment(
2809                    source_expression,
2810                    &source_expr.ty,
2811                    variable,
2812                );
2813            }
2814            let new_var = self.create_variable(variable, &source_expr.ty);
2815            ExpressionKind::VariableDefinition(new_var, Box::from(source_expr))
2816        };
2817
2818        let unit_type = self.shared.state.types.unit();
2819        self.create_expr(kind, unit_type, &variable.name)
2820    }
2821
2822    fn analyze_create_variable(
2823        &mut self,
2824        var: &swamp_ast::Variable,
2825        annotation_type: Option<&swamp_ast::Type>,
2826        source_expression: &swamp_ast::Expression,
2827    ) -> Expression {
2828        let maybe_annotated_type =
2829            annotation_type.map(|found_ast_type| self.analyze_type(found_ast_type));
2830
2831        let unsure_arg_context =
2832            TypeContext::new_unsure_argument(maybe_annotated_type.as_ref(), true);
2833
2834        let resolved_source = self.analyze_expression(source_expression, &unsure_arg_context);
2835
2836        let resulting_type = if let Some(annotated_type) = maybe_annotated_type {
2837            annotated_type
2838        } else {
2839            resolved_source.ty.clone()
2840        };
2841        let var_ref = self.create_local_variable(
2842            &var.name,
2843            Option::from(&var.is_mutable),
2844            &resulting_type,
2845            true,
2846        );
2847
2848        assert_ne!(&*resulting_type.kind, &TypeKind::Unit);
2849        let kind = ExpressionKind::VariableDefinition(var_ref, Box::from(resolved_source));
2850
2851        let unit_type = self.shared.state.types.unit();
2852
2853        self.create_expr(kind, unit_type, &var.name)
2854    }
2855
2856    fn add_location_item(
2857        &mut self,
2858        vec: &mut Vec<LocationAccess>,
2859        kind: LocationAccessKind,
2860        ty: TypeRef,
2861        ast_node: &swamp_ast::Node,
2862    ) {
2863        let resolved_node = self.to_node(ast_node);
2864        let postfix = LocationAccess {
2865            node: resolved_node,
2866            ty,
2867            kind,
2868        };
2869
2870        vec.push(postfix);
2871    }
2872
2873    fn extract_single_intrinsic_call(
2874        body: &Expression,
2875    ) -> Option<(IntrinsicFunction, Vec<ArgumentExpression>)> {
2876        if let ExpressionKind::Block(expressions) = &body.kind {
2877            let first_kind = &expressions[0].kind;
2878            if let ExpressionKind::IntrinsicCallEx(intrinsic_fn, args) = &first_kind {
2879                return Some((intrinsic_fn.clone(), args.clone()));
2880            }
2881        }
2882        None
2883    }
2884
2885    #[allow(clippy::too_many_lines)]
2886    fn analyze_chain_to_location(
2887        &mut self,
2888        chain: &swamp_ast::PostfixChain,
2889        context: &TypeContext,
2890        location_side: LocationSide,
2891    ) -> SingleLocationExpression {
2892        let mut items = Vec::new();
2893
2894        let nothing_context = TypeContext::new(None, true);
2895
2896        let base_expr = self.analyze_expression(&chain.base, &nothing_context);
2897        let ExpressionKind::VariableAccess(start_variable) = base_expr.kind else {
2898            self.add_err(ErrorKind::NotValidLocationStartingPoint, &chain.base.node);
2899            let unit_type = self.types().unit();
2900            let err_variable = Variable {
2901                name: Default::default(),
2902                assigned_name: String::new(),
2903                resolved_type: unit_type,
2904                mutable_node: None,
2905                variable_type: VariableType::Local,
2906                scope_index: 0,
2907                variable_index: 0,
2908                unique_id_within_function: 0,
2909                virtual_register: 0,
2910                is_unused: false,
2911            };
2912            return SingleLocationExpression {
2913                kind: MutableReferenceKind::MutVariableRef,
2914                node: self.to_node(&chain.base.node),
2915                ty: self.shared.state.types.unit(),
2916                starting_variable: VariableRef::from(err_variable),
2917                access_chain: vec![],
2918            };
2919        };
2920
2921        if !start_variable.is_mutable() {
2922            self.add_err(ErrorKind::VariableIsNotMutable, &chain.base.node);
2923
2924            let unit_type = self.types().unit();
2925            let err_variable = Variable {
2926                name: Default::default(),
2927                assigned_name: String::new(),
2928                resolved_type: unit_type,
2929                mutable_node: None,
2930                variable_type: VariableType::Local,
2931                scope_index: 0,
2932                variable_index: 0,
2933                unique_id_within_function: 0,
2934                virtual_register: 0,
2935                is_unused: false,
2936            };
2937            return SingleLocationExpression {
2938                kind: MutableReferenceKind::MutVariableRef,
2939                node: self.to_node(&chain.base.node),
2940                ty: self.shared.state.types.unit(),
2941                starting_variable: VariableRef::from(err_variable),
2942                access_chain: vec![],
2943            };
2944        }
2945
2946        let mut ty = start_variable.resolved_type.clone();
2947        for (i, item) in chain.postfixes.iter().enumerate() {
2948            let is_absolute_last_in_chain = i == chain.postfixes.len() - 1;
2949            match &item {
2950                swamp_ast::Postfix::FieldAccess(field_name_node) => {
2951                    //let field_name_resolved = self.to_node(field_name_node)
2952                    let (struct_type_ref, index, return_type) =
2953                        self.analyze_struct_field(field_name_node, &ty);
2954
2955                    self.add_location_item(
2956                        &mut items,
2957                        LocationAccessKind::FieldIndex(struct_type_ref.clone(), index),
2958                        return_type.clone(),
2959                        field_name_node,
2960                    );
2961
2962                    ty = return_type.clone();
2963                }
2964                swamp_ast::Postfix::SubscriptTuple(x_expr, y_expr) => match &*ty.kind {
2965                    TypeKind::GridView(element_type)
2966                    | TypeKind::GridStorage(element_type, _, _) => {
2967                        let int_type = self.types().int();
2968                        let unsigned_int_context = TypeContext::new_argument(&int_type, true);
2969                        let unsigned_int_x_expr =
2970                            self.analyze_expression(x_expr, &unsigned_int_context);
2971
2972                        let unsigned_int_y_expr =
2973                            self.analyze_expression(y_expr, &unsigned_int_context);
2974
2975                        let grid_type = GridType {
2976                            element: element_type.clone(),
2977                        };
2978
2979                        self.add_location_item(
2980                            &mut items,
2981                            LocationAccessKind::GridSubscript(
2982                                grid_type,
2983                                unsigned_int_x_expr,
2984                                unsigned_int_y_expr,
2985                            ),
2986                            element_type.clone(),
2987                            &x_expr.node,
2988                        );
2989
2990                        ty = element_type.clone();
2991                    }
2992                    _ => panic!("not allowed"),
2993                },
2994                swamp_ast::Postfix::Subscript(ast_key_expression) => {
2995                    let underlying = &ty.kind;
2996                    match &**underlying {
2997                        TypeKind::SliceView(element_type)
2998                        | TypeKind::StackStorage(element_type, _)
2999                        | TypeKind::StackView(element_type)
3000                        | TypeKind::VecStorage(element_type, _)
3001                        | TypeKind::DynamicLengthVecView(element_type)
3002                        | TypeKind::FixedCapacityAndLengthArray(element_type, _) => {
3003                            let int_type = self.types().int();
3004                            let unsigned_int_context = TypeContext::new_argument(&int_type, false);
3005                            let unsigned_int_expr =
3006                                self.analyze_expression(ast_key_expression, &unsigned_int_context);
3007
3008                            let slice_type = SliceViewType {
3009                                element: element_type.clone(),
3010                            };
3011
3012                            self.add_location_item(
3013                                &mut items,
3014                                LocationAccessKind::SliceViewSubscript(
3015                                    slice_type,
3016                                    unsigned_int_expr,
3017                                ),
3018                                element_type.clone(),
3019                                &ast_key_expression.node,
3020                            );
3021
3022                            ty = element_type.clone();
3023                        }
3024                        TypeKind::SparseView(element_type)
3025                        | TypeKind::SparseStorage(element_type, _) => {
3026                            let int_type = self.types().int();
3027                            let unsigned_int_context = TypeContext::new_argument(&int_type, false);
3028                            let unsigned_int_expr =
3029                                self.analyze_expression(ast_key_expression, &unsigned_int_context);
3030
3031                            let slice_type = SparseType {
3032                                element: element_type.clone(),
3033                            };
3034
3035                            self.add_location_item(
3036                                &mut items,
3037                                LocationAccessKind::SparseSubscript(slice_type, unsigned_int_expr),
3038                                element_type.clone(),
3039                                &ast_key_expression.node,
3040                            );
3041
3042                            ty = element_type.clone();
3043                        }
3044                        TypeKind::MapStorage(key_type, value_type, ..)
3045                        | TypeKind::DynamicLengthMapView(key_type, value_type) => {
3046                            let key_index_context = TypeContext::new_argument(key_type, false);
3047                            let key_expr =
3048                                self.analyze_expression(ast_key_expression, &key_index_context);
3049
3050                            let map_like_type = MapType {
3051                                key: key_type.clone(),
3052                                value: value_type.clone(),
3053                            };
3054
3055                            match location_side {
3056                                LocationSide::Lhs => {
3057                                    // Only if it is the absolute last subscript in the chain that we should
3058                                    // create a new map entry, otherwise we should just lookup an existing entry and get the
3059                                    // address to it.
3060                                    let access_kind = if is_absolute_last_in_chain {
3061                                        LocationAccessKind::MapSubscriptCreateIfNeeded(
3062                                            map_like_type,
3063                                            key_expr,
3064                                        )
3065                                    } else {
3066                                        LocationAccessKind::MapSubscriptMustExist(
3067                                            map_like_type,
3068                                            key_expr,
3069                                        )
3070                                    };
3071
3072                                    self.add_location_item(
3073                                        &mut items,
3074                                        access_kind,
3075                                        value_type.clone(),
3076                                        &ast_key_expression.node,
3077                                    );
3078                                }
3079                                LocationSide::Mutable | LocationSide::Rhs => {
3080                                    self.add_location_item(
3081                                        &mut items,
3082                                        LocationAccessKind::MapSubscriptMustExist(
3083                                            map_like_type,
3084                                            key_expr,
3085                                        ),
3086                                        value_type.clone(),
3087                                        &ast_key_expression.node,
3088                                    );
3089                                }
3090                            }
3091                            ty = value_type.clone();
3092                        }
3093
3094                        _ => {
3095                            eprintln!("can not subscript with this type: {underlying}");
3096                            todo!()
3097                        }
3098                    }
3099                }
3100
3101                swamp_ast::Postfix::MemberCall(node, _generic_arguments, _regular_args) => {
3102                    return SingleLocationExpression {
3103                        kind: MutableReferenceKind::MutVariableRef,
3104                        node: self.to_node(node),
3105                        ty: self.shared.state.types.unit(),
3106                        starting_variable: start_variable,
3107                        access_chain: vec![],
3108                    };
3109                }
3110                /*
3111                swamp_ast::Postfix::AdvancedFunctionCall(_, node, ..) => {
3112                    return Err(self.create_err(ErrorKind::CallsCanNotBePartOfChain, node));
3113                }
3114
3115                 */
3116                swamp_ast::Postfix::FunctionCall(node, _generic_arguments, _regular_args) => {
3117                    return SingleLocationExpression {
3118                        kind: MutableReferenceKind::MutVariableRef,
3119                        node: self.to_node(node),
3120                        ty: self.shared.state.types.unit(),
3121                        starting_variable: start_variable,
3122                        access_chain: vec![],
3123                    };
3124                }
3125                swamp_ast::Postfix::OptionalChainingOperator(node) => {
3126                    return SingleLocationExpression {
3127                        kind: MutableReferenceKind::MutVariableRef,
3128                        node: self.to_node(node),
3129                        ty: self.shared.state.types.unit(),
3130                        starting_variable: start_variable,
3131                        access_chain: vec![],
3132                    };
3133                }
3134                swamp_ast::Postfix::NoneCoalescingOperator(expr) => {
3135                    return SingleLocationExpression {
3136                        kind: MutableReferenceKind::MutVariableRef,
3137                        node: self.to_node(&expr.node),
3138                        ty: self.shared.state.types.unit(),
3139                        starting_variable: start_variable,
3140                        access_chain: vec![],
3141                    };
3142                }
3143            }
3144        }
3145
3146        if let Some(found_expected_type) = context.expected_type {
3147            if !self.types().compatible_with(found_expected_type, &ty) {
3148                self.add_err(
3149                    ErrorKind::IncompatibleTypes {
3150                        expected: found_expected_type.clone(),
3151                        found: ty.clone(),
3152                    },
3153                    &chain.base.node,
3154                );
3155            }
3156        }
3157
3158        SingleLocationExpression {
3159            kind: MutableReferenceKind::MutVariableRef,
3160            node: self.to_node(&chain.base.node),
3161            ty,
3162            starting_variable: start_variable,
3163            access_chain: items,
3164        }
3165    }
3166
3167    fn analyze_to_location(
3168        &mut self,
3169        expr: &swamp_ast::Expression,
3170        context: &TypeContext,
3171        location_type: LocationSide,
3172    ) -> SingleLocationExpression {
3173        match &expr.kind {
3174            swamp_ast::ExpressionKind::PostfixChain(chain) => {
3175                self.analyze_chain_to_location(chain, context, location_type)
3176            }
3177            swamp_ast::ExpressionKind::VariableReference(variable) => {
3178                let var = self.find_variable(variable);
3179                if !var.is_mutable() {
3180                    self.add_err(ErrorKind::VariableIsNotMutable, &expr.node);
3181                }
3182
3183                SingleLocationExpression {
3184                    kind: MutableReferenceKind::MutVariableRef,
3185                    node: self.to_node(&variable.name),
3186                    ty: var.resolved_type.clone(),
3187                    starting_variable: var,
3188                    access_chain: vec![],
3189                }
3190            }
3191            swamp_ast::ExpressionKind::IdentifierReference(qualified_identifier) => {
3192                let generated_var = swamp_ast::Variable {
3193                    name: qualified_identifier.name.clone(),
3194                    is_mutable: None,
3195                };
3196                let var = self.find_variable(&generated_var);
3197                if !var.is_mutable() {
3198                    self.add_err(ErrorKind::VariableIsNotMutable, &expr.node);
3199                }
3200                SingleLocationExpression {
3201                    kind: MutableReferenceKind::MutVariableRef,
3202                    node: self.to_node(&generated_var.name),
3203                    ty: var.resolved_type.clone(),
3204                    starting_variable: var,
3205                    access_chain: vec![],
3206                }
3207            }
3208            _ => {
3209                self.add_err(ErrorKind::NotValidLocationStartingPoint, &expr.node);
3210                let unit_type = self.types().unit();
3211                SingleLocationExpression {
3212                    kind: MutableReferenceKind::MutVariableRef,
3213                    node: self.to_node(&expr.node),
3214                    ty: unit_type.clone(),
3215                    starting_variable: Rc::new(Variable {
3216                        name: Default::default(),
3217                        assigned_name: String::new(),
3218                        resolved_type: unit_type,
3219                        mutable_node: None,
3220                        variable_type: VariableType::Local,
3221                        scope_index: 0,
3222                        variable_index: 0,
3223                        unique_id_within_function: 0,
3224                        virtual_register: 0,
3225                        is_unused: false,
3226                    }),
3227                    access_chain: vec![],
3228                }
3229            }
3230        }
3231    }
3232
3233    fn analyze_expression_for_assignment_compound(
3234        &mut self,
3235        target_expression: &swamp_ast::Expression,
3236        ast_source_expression: &swamp_ast::Expression,
3237    ) -> (TargetAssignmentLocation, Expression) {
3238        let any_argument_context = TypeContext::new_anything_argument(true);
3239        let source_expr = self.analyze_expression(ast_source_expression, &any_argument_context);
3240        let source_expr_type_context = TypeContext::new_argument(&source_expr.ty, true);
3241
3242        let resolved_location = TargetAssignmentLocation(self.analyze_to_location(
3243            target_expression,
3244            &source_expr_type_context,
3245            LocationSide::Rhs,
3246        ));
3247
3248        (resolved_location, source_expr)
3249    }
3250
3251    /*
3252    fn try_convert_for_assignment(
3253        &mut self,
3254        expr: &Expression,
3255        target_type: &TypeRef,
3256        ast_node: &swamp_ast::Expression,
3257    ) -> Result<Option<Expression>, Error> {
3258        match (target_type, &expr.ty) {
3259            // Conversion cases that require transformation
3260            (TypeKind::VecStorage(target_elem, capacity), TypeKind::FixedSlice(source_elem, _)) => {
3261                // Create conversion with checks
3262                // ...
3263            }
3264
3265            (TypeKind::String, TypeKind::Int) => {
3266                // Create int-to-string conversion
3267                // ...
3268            }
3269
3270            // No conversion possible
3271            _ => Ok(None),
3272        }
3273    }
3274
3275     */
3276
3277    fn analyze_expression_for_assignment_with_target_type(
3278        &mut self,
3279        target_type: &TypeRef,
3280        ast_source_expression: &swamp_ast::Expression,
3281    ) -> Expression {
3282        let base_context = TypeContext::new_argument(target_type, true);
3283        let source_expr = self.analyze_expression(ast_source_expression, &base_context);
3284
3285        let final_expr = if self.types().compatible_with(target_type, &source_expr.ty) {
3286            source_expr
3287        } else {
3288            let source_type = source_expr.ty.clone();
3289            self.types_did_not_match_try_late_coerce_expression(
3290                source_expr,
3291                target_type,
3292                &source_type,
3293                &ast_source_expression.node,
3294            )
3295        };
3296
3297        let assignment_mode = self.check_assignment_mode(true, &final_expr, target_type); // TODO: Fill in correct lhs_is_mutable
3298
3299        self.check_mutable_assignment(assignment_mode, &final_expr.node);
3300
3301        final_expr
3302    }
3303
3304    fn analyze_expression_for_assignment(
3305        &mut self,
3306        ast_target_location_expression: &swamp_ast::Expression,
3307        ast_source_expression: &swamp_ast::Expression,
3308    ) -> (TargetAssignmentLocation, Expression) {
3309        let any_argument_context = TypeContext::new_anything_argument(true);
3310        let resolved_location = self.analyze_to_location(
3311            ast_target_location_expression,
3312            &any_argument_context,
3313            LocationSide::Lhs,
3314        );
3315
3316        let target_type = resolved_location.ty.clone();
3317        let mut_type = target_type; // Mutable references now use the same type
3318        let mut_location = TargetAssignmentLocation(resolved_location);
3319
3320        let final_expr = self
3321            .analyze_expression_for_assignment_with_target_type(&mut_type, ast_source_expression);
3322
3323        (mut_location, final_expr)
3324    }
3325
3326    fn analyze_assignment_compound(
3327        &mut self,
3328        target_expression: &swamp_ast::Expression,
3329        ast_op: &swamp_ast::CompoundOperator,
3330        ast_source_expression: &swamp_ast::Expression,
3331    ) -> Expression {
3332        let resolved_op = self.analyze_compound_operator(ast_op);
3333
3334        let (resolved_location, source_expr) = self
3335            .analyze_expression_for_assignment_compound(target_expression, ast_source_expression);
3336
3337        let kind = ExpressionKind::CompoundAssignment(
3338            resolved_location,
3339            resolved_op.kind,
3340            Box::from(source_expr),
3341        );
3342
3343        let unit_type = self.shared.state.types.unit();
3344
3345        self.create_expr(kind, unit_type, &target_expression.node)
3346    }
3347
3348    fn analyze_assignment_mode(lhs: SingleLocationExpression) {}
3349
3350    fn analyze_assignment(
3351        &mut self,
3352        target_location: &swamp_ast::Expression,
3353        ast_source_expression: &swamp_ast::Expression,
3354    ) -> Expression {
3355        let (mut_location, source_expr) =
3356            self.analyze_expression_for_assignment(target_location, ast_source_expression);
3357        let kind = ExpressionKind::Assignment(Box::from(mut_location), Box::from(source_expr));
3358        let unit_type = self.shared.state.types.unit();
3359
3360        // Assignments are always of type Unit
3361
3362        self.create_expr(kind, unit_type, &target_location.node)
3363    }
3364
3365    #[must_use]
3366    pub const fn create_expr(
3367        &self,
3368        kind: ExpressionKind,
3369        ty: TypeRef,
3370        ast_node: &swamp_ast::Node,
3371    ) -> Expression {
3372        //info!(%ty, ?kind, "create_expr()");
3373        Expression {
3374            kind,
3375            ty,
3376            node: self.to_node(ast_node),
3377        }
3378    }
3379
3380    fn analyze_destructuring(
3381        &mut self,
3382        node: &swamp_ast::Node,
3383        target_ast_variables: &[swamp_ast::Variable],
3384        tuple_expression: &swamp_ast::Expression,
3385    ) -> Expression {
3386        let any_context = TypeContext::new_anything_argument(true);
3387        let tuple_resolved = self.analyze_expression(tuple_expression, &any_context);
3388        let tuple_expr_type = &tuple_resolved.ty;
3389        let unit = self.types().unit();
3390
3391        let mut variable_refs = Vec::new();
3392        if let TypeKind::Tuple(tuple) = &*tuple_expr_type.kind {
3393            if target_ast_variables.len() > tuple.len() {
3394                return self.create_err(ErrorKind::TooManyDestructureVariables, node);
3395            }
3396            for (ast_variable, tuple_type) in target_ast_variables.iter().zip(tuple.clone()) {
3397                let variable_ref = self.create_local_variable(
3398                    &ast_variable.name,
3399                    ast_variable.is_mutable.as_ref(),
3400                    &tuple_type,
3401                    true,
3402                );
3403                variable_refs.push(variable_ref);
3404            }
3405            let expr_kind = ExpressionKind::TupleDestructuring(
3406                variable_refs,
3407                tuple_expr_type.clone(),
3408                Box::from(tuple_resolved),
3409            );
3410
3411            self.create_expr(expr_kind, unit, node)
3412        } else {
3413            self.create_err(ErrorKind::CanNotDestructure, node)
3414        }
3415    }
3416
3417    fn analyze_normal_member_call(
3418        &mut self,
3419        type_that_member_is_on: &TypeRef,
3420        found_function: &FunctionRef,
3421        generic_arguments: Vec<TypeRef>,
3422        ast_arguments: &[swamp_ast::Expression],
3423        is_mutable: bool,
3424        node: &swamp_ast::Node,
3425    ) -> Signature {
3426        let resolved_node = self.to_node(node);
3427        // TODO:
3428
3429        found_function.signature().clone()
3430    }
3431
3432    fn queue_member_signature(
3433        &mut self,
3434        self_type: &TypeRef,
3435        key_type: Option<&TypeRef>,
3436        element_type: &TypeRef,
3437        field_name_str: &str,
3438        lambda_variable_count: usize,
3439        node: &swamp_ast::Node,
3440    ) -> Option<(IntrinsicFunction, Signature)> {
3441        let self_type_param = TypeForParameter {
3442            name: "self".to_string(),
3443            resolved_type: self_type.clone(),
3444            is_mutable: false,
3445            node: None,
3446        };
3447        let self_mutable_type_param = TypeForParameter {
3448            name: "self".to_string(),
3449            resolved_type: self_type.clone(),
3450            is_mutable: true,
3451            node: None,
3452        };
3453        let intrinsic_and_signature = match field_name_str {
3454            "enqueue" => (
3455                IntrinsicFunction::VecPush,
3456                Signature {
3457                    parameters: vec![
3458                        self_mutable_type_param,
3459                        TypeForParameter {
3460                            name: "element".to_string(),
3461                            resolved_type: element_type.clone(),
3462                            is_mutable: false,
3463                            node: None,
3464                        },
3465                    ],
3466                    return_type: self.types().unit(),
3467                },
3468            ),
3469            "dequeue" => (
3470                IntrinsicFunction::VecRemoveFirstIndexGetValue,
3471                Signature {
3472                    parameters: vec![self_mutable_type_param],
3473                    return_type: element_type.clone(),
3474                },
3475            ),
3476            _ => {
3477                self.slice_member_signature(
3478                    self_type,
3479                    key_type,
3480                    element_type,
3481                    field_name_str,
3482                    lambda_variable_count,
3483                    node,
3484                )
3485            }?,
3486        };
3487
3488        Some(intrinsic_and_signature)
3489    }
3490
3491    fn sparse_member_signature(
3492        &mut self,
3493        self_type: &TypeRef,
3494        element_type: &TypeRef,
3495        field_name_str: &str,
3496        lambda_variable_count: usize,
3497        node: &swamp_ast::Node,
3498    ) -> Option<(IntrinsicFunction, Signature)> {
3499        let key_type = self.types().int(); // TODO: SparseID
3500
3501        let self_type_param = TypeForParameter {
3502            name: "self".to_string(),
3503            resolved_type: self_type.clone(),
3504            is_mutable: false,
3505            node: None,
3506        };
3507        let self_mutable_type_param = TypeForParameter {
3508            name: "self".to_string(),
3509            resolved_type: self_type.clone(),
3510            is_mutable: true,
3511            node: None,
3512        };
3513        let intrinsic_and_signature = match field_name_str {
3514            "add" => (
3515                IntrinsicFunction::SparseAdd,
3516                Signature {
3517                    parameters: vec![
3518                        self_mutable_type_param,
3519                        TypeForParameter {
3520                            name: "element".to_string(),
3521                            resolved_type: element_type.clone(),
3522                            is_mutable: false,
3523                            node: None,
3524                        },
3525                    ],
3526                    return_type: self.types().int(),
3527                },
3528            ),
3529            "remove" => (
3530                IntrinsicFunction::SparseRemove,
3531                Signature {
3532                    parameters: vec![
3533                        self_mutable_type_param,
3534                        TypeForParameter {
3535                            name: "key".to_string(),
3536                            resolved_type: key_type,
3537                            is_mutable: false,
3538                            node: None,
3539                        },
3540                    ],
3541                    return_type: self.types().unit(),
3542                },
3543            ),
3544            "is_alive" => (
3545                IntrinsicFunction::SparseIsAlive,
3546                Signature {
3547                    parameters: vec![
3548                        self_type_param,
3549                        TypeForParameter {
3550                            name: "element".to_string(),
3551                            resolved_type: element_type.clone(),
3552                            is_mutable: false,
3553                            node: None,
3554                        },
3555                    ],
3556                    return_type: self.types().bool(),
3557                },
3558            ),
3559
3560            _ => {
3561                self.slice_member_signature(
3562                    self_type,
3563                    Option::from(key_type).as_ref(),
3564                    element_type,
3565                    field_name_str,
3566                    lambda_variable_count,
3567                    node,
3568                )
3569            }?,
3570        };
3571        Some(intrinsic_and_signature)
3572    }
3573
3574    fn vec_member_signature(
3575        &mut self,
3576        self_type: &TypeRef,
3577        element_type: &TypeRef,
3578        field_name_str: &str,
3579        lambda_variable_count: usize,
3580        node: &swamp_ast::Node,
3581    ) -> Option<(IntrinsicFunction, Signature)> {
3582        let key_type = self.types().int();
3583        let self_type_param = TypeForParameter {
3584            name: "self".to_string(),
3585            resolved_type: self_type.clone(),
3586            is_mutable: false,
3587            node: None,
3588        };
3589        let self_mutable_type_param = TypeForParameter {
3590            name: "self".to_string(),
3591            resolved_type: self_type.clone(),
3592            is_mutable: true,
3593            node: None,
3594        };
3595        let intrinsic_and_signature = match field_name_str {
3596            "prepend" => (
3597                IntrinsicFunction::VecPush,
3598                Signature {
3599                    parameters: vec![
3600                        self_mutable_type_param,
3601                        TypeForParameter {
3602                            name: "element".to_string(),
3603                            resolved_type: element_type.clone(),
3604                            is_mutable: false,
3605                            node: None,
3606                        },
3607                    ],
3608                    return_type: self.types().unit(),
3609                },
3610            ),
3611            "push" => (
3612                IntrinsicFunction::VecPush,
3613                Signature {
3614                    parameters: vec![
3615                        self_mutable_type_param,
3616                        TypeForParameter {
3617                            name: "element".to_string(),
3618                            resolved_type: element_type.clone(),
3619                            is_mutable: false,
3620                            node: None,
3621                        },
3622                    ],
3623                    return_type: self.types().unit(),
3624                },
3625            ),
3626            "pop" => (
3627                IntrinsicFunction::VecPop,
3628                Signature {
3629                    parameters: vec![self_mutable_type_param],
3630                    return_type: element_type.clone(),
3631                },
3632            ),
3633
3634            _ => {
3635                self.slice_member_signature(
3636                    self_type,
3637                    Option::from(key_type).as_ref(),
3638                    element_type,
3639                    field_name_str,
3640                    lambda_variable_count,
3641                    node,
3642                )
3643            }?,
3644        };
3645        Some(intrinsic_and_signature)
3646    }
3647
3648    #[allow(clippy::unnecessary_wraps)]
3649    fn grid_member_signature(
3650        &mut self,
3651        self_type: &TypeRef,
3652        element_type: &TypeRef,
3653        field_name_str: &str,
3654        node: &swamp_ast::Node,
3655    ) -> Option<(IntrinsicFunction, Signature)> {
3656        let self_type_param = TypeForParameter {
3657            name: "self".to_string(),
3658            resolved_type: self_type.clone(),
3659            is_mutable: false,
3660            node: None,
3661        };
3662        let self_mutable_type_param = TypeForParameter {
3663            name: "self".to_string(),
3664            resolved_type: self_type.clone(),
3665            is_mutable: true,
3666            node: None,
3667        };
3668        let element_param = TypeForParameter {
3669            name: "element".to_string(),
3670            resolved_type: element_type.clone(),
3671            is_mutable: false,
3672            node: None,
3673        };
3674        let int_type = self.types().int();
3675
3676        let int_param = TypeForParameter {
3677            name: "x_or_y".to_string(),
3678            resolved_type: int_type.clone(),
3679            is_mutable: false,
3680            node: None,
3681        };
3682        let intrinsic_and_signature = match field_name_str {
3683            "set" => (
3684                IntrinsicFunction::GridSet,
3685                Signature {
3686                    parameters: vec![self_type_param, int_param.clone(), int_param, element_param],
3687                    return_type: self.types().unit(),
3688                },
3689            ),
3690
3691            "get" => (
3692                IntrinsicFunction::GridGet,
3693                Signature {
3694                    parameters: vec![self_type_param, int_param.clone(), int_param],
3695                    return_type: element_type.clone(),
3696                },
3697            ),
3698
3699            "width" => (
3700                IntrinsicFunction::GridWidth,
3701                Signature {
3702                    parameters: vec![self_type_param],
3703                    return_type: int_type,
3704                },
3705            ),
3706
3707            "height" => (
3708                IntrinsicFunction::GridHeight,
3709                Signature {
3710                    parameters: vec![self_type_param],
3711                    return_type: int_type,
3712                },
3713            ),
3714
3715            _ => panic!("unknown grid method {field_name_str}"),
3716        };
3717
3718        Some(intrinsic_and_signature)
3719    }
3720
3721    fn basic_collection_member_signature(
3722        &mut self,
3723        self_type: &TypeRef,
3724        field_name_str: &str,
3725        node: &swamp_ast::Node,
3726    ) -> Option<(IntrinsicFunction, Signature)> {
3727        let self_type_param = TypeForParameter {
3728            name: "self".to_string(),
3729            resolved_type: self_type.clone(),
3730            is_mutable: false,
3731            node: None,
3732        };
3733        let self_mut_type_param = TypeForParameter {
3734            name: "self".to_string(),
3735            resolved_type: self_type.clone(),
3736            is_mutable: true,
3737            node: None,
3738        };
3739        let intrinsic_and_signature = match field_name_str {
3740            "len" => {
3741                let signature = Signature {
3742                    parameters: vec![self_type_param],
3743                    return_type: self.types().int(),
3744                };
3745                (IntrinsicFunction::VecLen, signature)
3746            }
3747            "is_empty" => (
3748                IntrinsicFunction::VecIsEmpty,
3749                Signature {
3750                    parameters: vec![self_type_param],
3751                    return_type: self.types().bool(),
3752                },
3753            ),
3754            "capacity" => {
3755                let signature = Signature {
3756                    parameters: vec![self_type_param],
3757                    return_type: self.types().int(),
3758                };
3759                (IntrinsicFunction::VecCapacity, signature)
3760            }
3761            _ => {
3762                self.add_err(ErrorKind::UnknownMemberFunction(self_type.clone()), node);
3763
3764                return None;
3765            }
3766        };
3767        Some(intrinsic_and_signature)
3768    }
3769    #[allow(clippy::too_many_lines)]
3770    fn codepoint_member_signature(
3771        &mut self,
3772        self_type: &TypeRef,
3773        key_type: Option<&TypeRef>,
3774        element_type: &TypeRef,
3775        field_name_str: &str,
3776        lambda_variable_count: usize,
3777        node: &swamp_ast::Node,
3778    ) -> Option<(IntrinsicFunction, Signature)> {
3779        let self_type_param = TypeForParameter {
3780            name: "self".to_string(),
3781            resolved_type: self_type.clone(),
3782            is_mutable: false,
3783            node: None,
3784        };
3785
3786        match field_name_str {
3787            "to_int" => Some((
3788                IntrinsicFunction::CodepointToInt,
3789                Signature {
3790                    parameters: vec![self_type_param],
3791                    return_type: self.types().int(),
3792                },
3793            )),
3794            _ => None,
3795        }
3796    }
3797
3798    #[allow(clippy::too_many_lines)]
3799    fn byte_member_signature(
3800        &mut self,
3801        self_type: &TypeRef,
3802        key_type: Option<&TypeRef>,
3803        element_type: &TypeRef,
3804        field_name_str: &str,
3805        lambda_variable_count: usize,
3806        node: &swamp_ast::Node,
3807    ) -> Option<(IntrinsicFunction, Signature)> {
3808        let self_type_param = TypeForParameter {
3809            name: "self".to_string(),
3810            resolved_type: self_type.clone(),
3811            is_mutable: false,
3812            node: None,
3813        };
3814
3815        match field_name_str {
3816            "to_int" => Some((
3817                IntrinsicFunction::ByteToInt,
3818                Signature {
3819                    parameters: vec![self_type_param],
3820                    return_type: self.types().int(),
3821                },
3822            )),
3823            _ => None,
3824        }
3825    }
3826
3827    #[allow(clippy::too_many_lines)]
3828    fn string_member_signature(
3829        &mut self,
3830        self_type: &TypeRef,
3831        key_type: Option<&TypeRef>,
3832        element_type: &TypeRef,
3833        field_name_str: &str,
3834        lambda_variable_count: usize,
3835        node: &swamp_ast::Node,
3836    ) -> Option<(IntrinsicFunction, Signature)> {
3837        self.vec_member_signature(
3838            self_type,
3839            element_type,
3840            field_name_str,
3841            lambda_variable_count,
3842            node,
3843        )
3844    }
3845
3846    #[allow(clippy::too_many_lines)]
3847    fn slice_member_signature(
3848        &mut self,
3849        self_type: &TypeRef,
3850        key_type: Option<&TypeRef>,
3851        element_type: &TypeRef,
3852        field_name_str: &str,
3853        lambda_variable_count: usize,
3854        node: &swamp_ast::Node,
3855    ) -> Option<(IntrinsicFunction, Signature)> {
3856        let slice_view_type = self.types().slice_view(&element_type.clone());
3857        let int_type = self.types().int();
3858        let self_type_param = TypeForParameter {
3859            name: "self".to_string(),
3860            resolved_type: slice_view_type.clone(),
3861            is_mutable: false,
3862            node: None,
3863        };
3864        let self_mut_type_param = TypeForParameter {
3865            name: "self".to_string(),
3866            resolved_type: slice_view_type,
3867            is_mutable: true,
3868            node: None,
3869        };
3870        let intrinsic_and_signature = match field_name_str {
3871            "for" => {
3872                let parameters = if lambda_variable_count == 2 {
3873                    vec![
3874                        TypeForParameter {
3875                            name: "key".to_string(),
3876                            resolved_type: key_type.unwrap().clone(),
3877                            is_mutable: false,
3878                            node: None,
3879                        },
3880                        TypeForParameter {
3881                            name: "element".to_string(),
3882                            resolved_type: element_type.clone(),
3883                            is_mutable: false,
3884                            node: None,
3885                        },
3886                    ]
3887                } else {
3888                    vec![TypeForParameter {
3889                        name: "element".to_string(),
3890                        resolved_type: element_type.clone(),
3891                        is_mutable: false,
3892                        node: None,
3893                    }]
3894                };
3895                let lambda_signature = Signature {
3896                    parameters,
3897                    return_type: self.types().unit(),
3898                };
3899                let lambda_function_type = self.types().function(lambda_signature);
3900                (
3901                    IntrinsicFunction::TransformerFor,
3902                    Signature {
3903                        parameters: vec![
3904                            self_type_param,
3905                            TypeForParameter {
3906                                name: "lambda".to_string(),
3907                                resolved_type: lambda_function_type,
3908                                is_mutable: false,
3909                                node: None,
3910                            },
3911                        ],
3912                        return_type: self.types().unit(), // VecFor is only used for side effects
3913                    },
3914                )
3915            }
3916            "while" => {
3917                let parameters = if lambda_variable_count == 2 {
3918                    vec![
3919                        TypeForParameter {
3920                            name: "key".to_string(),
3921                            resolved_type: key_type.unwrap().clone(),
3922                            is_mutable: false,
3923                            node: None,
3924                        },
3925                        TypeForParameter {
3926                            name: "element".to_string(),
3927                            resolved_type: element_type.clone(),
3928                            is_mutable: false,
3929                            node: None,
3930                        },
3931                    ]
3932                } else {
3933                    vec![TypeForParameter {
3934                        name: "element".to_string(),
3935                        resolved_type: element_type.clone(),
3936                        is_mutable: false,
3937                        node: None,
3938                    }]
3939                };
3940                let lambda_signature = Signature {
3941                    parameters,
3942                    return_type: self.types().bool(), // it returns if the while loop should continue
3943                };
3944                let lambda_function_type = self.types().function(lambda_signature);
3945                (
3946                    IntrinsicFunction::TransformerWhile,
3947                    Signature {
3948                        parameters: vec![
3949                            self_type_param,
3950                            TypeForParameter {
3951                                name: "lambda".to_string(),
3952                                resolved_type: lambda_function_type,
3953                                is_mutable: false,
3954                                node: None,
3955                            },
3956                        ],
3957                        return_type: self.types().unit(), // VecFor is only used for side effects
3958                    },
3959                )
3960            }
3961            "filter" => {
3962                let lambda_signature = Signature {
3963                    parameters: vec![TypeForParameter {
3964                        name: "element".to_string(),
3965                        resolved_type: element_type.clone(),
3966                        is_mutable: false,
3967                        node: None,
3968                    }],
3969                    return_type: self.types().bool(),
3970                };
3971                let lambda_function_type = self.types().function(lambda_signature);
3972                (
3973                    IntrinsicFunction::TransformerFilter,
3974                    Signature {
3975                        parameters: vec![
3976                            self_type_param,
3977                            TypeForParameter {
3978                                name: "lambda".to_string(),
3979                                resolved_type: lambda_function_type,
3980                                is_mutable: false,
3981                                node: None,
3982                            },
3983                        ],
3984                        return_type: self.shared.state.types.slice_view(&element_type.clone()),
3985                    },
3986                )
3987            }
3988            "find" => {
3989                let lambda_signature = Signature {
3990                    parameters: vec![TypeForParameter {
3991                        name: "element".to_string(),
3992                        resolved_type: element_type.clone(),
3993                        is_mutable: false,
3994                        node: None,
3995                    }],
3996                    return_type: self.types().bool(),
3997                };
3998                let lambda_function_type = self.types().function(lambda_signature);
3999                (
4000                    IntrinsicFunction::TransformerFind,
4001                    Signature {
4002                        parameters: vec![
4003                            self_type_param,
4004                            TypeForParameter {
4005                                name: "lambda".to_string(),
4006                                resolved_type: lambda_function_type,
4007                                is_mutable: false,
4008                                node: None,
4009                            },
4010                        ],
4011                        return_type: self.shared.state.types.optional(&element_type.clone()),
4012                    },
4013                )
4014            }
4015
4016            "remove" => {
4017                let signature = Signature {
4018                    parameters: vec![
4019                        self_mut_type_param,
4020                        TypeForParameter {
4021                            name: "index".to_string(),
4022                            resolved_type: int_type,
4023                            is_mutable: false,
4024                            node: None,
4025                        },
4026                    ],
4027                    return_type: self.types().unit(),
4028                };
4029                (IntrinsicFunction::VecRemoveIndex, signature)
4030            }
4031            _ => return self.basic_collection_member_signature(self_type, field_name_str, node),
4032        };
4033        Some(intrinsic_and_signature)
4034    }
4035
4036    #[allow(clippy::unnecessary_wraps, clippy::result_large_err)]
4037    fn map_member_signature(
4038        &mut self,
4039        self_type: &TypeRef,
4040        key_type: &TypeRef,
4041        value_type: &TypeRef,
4042        field_name_str: &str,
4043        node: &swamp_ast::Node,
4044    ) -> Option<(IntrinsicFunction, Signature)> {
4045        let self_type_param = TypeForParameter {
4046            name: "self".to_string(),
4047            resolved_type: self_type.clone(),
4048            is_mutable: false,
4049            node: None,
4050        };
4051
4052        let mutable_self_type_param = TypeForParameter {
4053            name: "self".to_string(),
4054            resolved_type: self_type.clone(),
4055            is_mutable: true,
4056            node: None,
4057        };
4058
4059        let intrinsic_and_signature = match field_name_str {
4060            "has" => (
4061                IntrinsicFunction::MapHas,
4062                Signature {
4063                    parameters: vec![
4064                        self_type_param,
4065                        TypeForParameter {
4066                            name: "key".to_string(),
4067                            resolved_type: key_type.clone(),
4068                            is_mutable: false,
4069                            node: None,
4070                        },
4071                    ],
4072                    return_type: self.types().bool(),
4073                },
4074            ),
4075            "remove" => (
4076                IntrinsicFunction::MapRemove,
4077                Signature {
4078                    parameters: vec![
4079                        mutable_self_type_param,
4080                        TypeForParameter {
4081                            name: "key".to_string(),
4082                            resolved_type: key_type.clone(),
4083                            is_mutable: false,
4084                            node: None,
4085                        },
4086                    ],
4087                    return_type: self.types().unit(),
4088                },
4089            ),
4090            "len" => (
4091                IntrinsicFunction::MapLen,
4092                Signature {
4093                    parameters: vec![self_type_param],
4094                    return_type: self.types().int(),
4095                },
4096            ),
4097            "capacity" => (
4098                IntrinsicFunction::MapCapacity,
4099                Signature {
4100                    parameters: vec![self_type_param],
4101                    return_type: self.types().int(),
4102                },
4103            ),
4104            "is_empty" => (
4105                IntrinsicFunction::MapIsEmpty,
4106                Signature {
4107                    parameters: vec![self_type_param],
4108                    return_type: self.types().bool(),
4109                },
4110            ),
4111            _ => todo!("unknown map member"),
4112        };
4113
4114        Some(intrinsic_and_signature)
4115    }
4116
4117    fn check_intrinsic_member_signature(
4118        &mut self,
4119        type_that_member_is_on: &TypeRef,
4120        field_name_str: &str,
4121        lambda_variables_count: usize,
4122        node: &swamp_ast::Node,
4123    ) -> Option<(IntrinsicFunction, Signature)> {
4124        let ty = type_that_member_is_on;
4125        let int_type = self.types().int();
4126        match &*ty.kind {
4127            TypeKind::GridStorage(element_type, ..) | TypeKind::GridView(element_type) => self
4128                .grid_member_signature(type_that_member_is_on, element_type, field_name_str, node),
4129            TypeKind::SparseStorage(element_type, ..) | TypeKind::SparseView(element_type) => self
4130                .sparse_member_signature(
4131                    type_that_member_is_on,
4132                    element_type,
4133                    field_name_str,
4134                    lambda_variables_count,
4135                    node,
4136                ),
4137            TypeKind::QueueStorage(element_type, ..) => self.queue_member_signature(
4138                type_that_member_is_on,
4139                None,
4140                element_type,
4141                field_name_str,
4142                lambda_variables_count,
4143                node,
4144            ),
4145            TypeKind::StackStorage(element_type, ..)
4146            | TypeKind::QueueStorage(element_type, ..)
4147            | TypeKind::VecStorage(element_type, ..)
4148            | TypeKind::DynamicLengthVecView(element_type) => self.vec_member_signature(
4149                type_that_member_is_on,
4150                element_type,
4151                field_name_str,
4152                lambda_variables_count,
4153                node,
4154            ),
4155            TypeKind::SliceView(element_type) => self.slice_member_signature(
4156                type_that_member_is_on,
4157                Some(&int_type),
4158                element_type,
4159                field_name_str,
4160                lambda_variables_count,
4161                node,
4162            ),
4163            TypeKind::Byte => {
4164                let element_type = self.shared.state.types.byte();
4165                self.byte_member_signature(
4166                    type_that_member_is_on,
4167                    Some(&int_type),
4168                    &element_type,
4169                    field_name_str,
4170                    lambda_variables_count,
4171                    node,
4172                )
4173            }
4174            TypeKind::Codepoint => {
4175                let element_type = self.shared.state.types.codepoint();
4176                self.codepoint_member_signature(
4177                    type_that_member_is_on,
4178                    Some(&int_type),
4179                    &element_type,
4180                    field_name_str,
4181                    lambda_variables_count,
4182                    node,
4183                )
4184            }
4185            TypeKind::String { .. } | TypeKind::StringStorage(..) => {
4186                let element_type = self.shared.state.types.byte();
4187                self.string_member_signature(
4188                    type_that_member_is_on,
4189                    Some(&int_type),
4190                    &element_type,
4191                    field_name_str,
4192                    lambda_variables_count,
4193                    node,
4194                )
4195            }
4196            TypeKind::DynamicLengthMapView(key, value) | TypeKind::MapStorage(key, value, _) => {
4197                self.map_member_signature(type_that_member_is_on, key, value, field_name_str, node)
4198            }
4199
4200            TypeKind::FixedCapacityAndLengthArray(element_type, _) => self.slice_member_signature(
4201                type_that_member_is_on,
4202                Some(&int_type),
4203                element_type,
4204                field_name_str,
4205                lambda_variables_count,
4206                node,
4207            ),
4208            _ => {
4209                self.add_err(
4210                    ErrorKind::UnknownMemberFunction(type_that_member_is_on.clone()),
4211                    node,
4212                );
4213
4214                None
4215            }
4216        }
4217    }
4218
4219    fn analyze_member_call(
4220        &mut self,
4221        type_that_member_is_on: &TypeRef,
4222        field_name_str: &str,
4223        ast_maybe_generic_arguments: Option<Vec<swamp_ast::GenericParameter>>,
4224        ast_arguments: &[swamp_ast::Expression],
4225        chain_self_is_mutable: bool,
4226        node: &swamp_ast::Node,
4227    ) -> (PostfixKind, TypeRef) {
4228        let generic_arguments = if let Some(ast_generic_arguments) = ast_maybe_generic_arguments {
4229            let mut resolved_types = Vec::new();
4230            for ast_type in ast_generic_arguments {
4231                resolved_types.push(self.analyze_type(ast_type.get_type()));
4232            }
4233            resolved_types
4234        } else {
4235            vec![]
4236        };
4237
4238        let maybe_function = self
4239            .shared
4240            .state
4241            .associated_impls
4242            .get_member_function(type_that_member_is_on, field_name_str)
4243            .cloned();
4244
4245        let (function_ref, instantiated_signature) = if let Some(found_function) = maybe_function {
4246            let signature = self.analyze_normal_member_call(
4247                type_that_member_is_on,
4248                &found_function,
4249                generic_arguments,
4250                ast_arguments,
4251                chain_self_is_mutable,
4252                node,
4253            );
4254            (found_function, signature)
4255        } else {
4256            let lambda_variables_count = if ast_arguments.is_empty() {
4257                0
4258            } else if let swamp_ast::ExpressionKind::Lambda(variables, ..) = &ast_arguments[0].kind
4259            {
4260                variables.len()
4261            } else {
4262                0
4263            };
4264            let Some((intrinsic_fn, signature)) = self.check_intrinsic_member_signature(
4265                type_that_member_is_on,
4266                field_name_str,
4267                lambda_variables_count,
4268                node,
4269            ) else {
4270                return (PostfixKind::OptionalChainingOperator, self.types().unit());
4271            };
4272            let def = IntrinsicFunctionDefinition {
4273                name: field_name_str.to_string(),
4274                signature,
4275                intrinsic: intrinsic_fn,
4276            };
4277            let function_ref = FunctionRef::from(Function::Intrinsic(
4278                IntrinsicFunctionDefinitionRef::from(def.clone()),
4279            ));
4280            (function_ref, def.signature)
4281        };
4282
4283        let self_type_in_signature = &instantiated_signature.parameters[0];
4284
4285        if self_type_in_signature.is_mutable && !chain_self_is_mutable {
4286            self.add_err(ErrorKind::SelfNotCorrectMutableState, node);
4287        }
4288
4289        let resolved_arguments = self.analyze_and_verify_parameters(
4290            node,
4291            &instantiated_signature.parameters[1..],
4292            ast_arguments,
4293        );
4294
4295        (
4296            PostfixKind::MemberCall(function_ref, resolved_arguments),
4297            TypeRef::from(instantiated_signature.return_type.clone()),
4298        )
4299    }
4300
4301    fn analyze_postfix_member_call(
4302        &mut self,
4303        type_that_member_is_on: &TypeRef,
4304        is_mutable: bool,
4305        member_name: &swamp_ast::Node,
4306        ast_maybe_generic_arguments: Option<Vec<swamp_ast::GenericParameter>>,
4307        ast_arguments: &[swamp_ast::Expression],
4308        suffixes: &mut Vec<Postfix>,
4309    ) -> TypeRef {
4310        let field_name_str = self.get_text(member_name).to_string();
4311
4312        let resolved_node = self.to_node(member_name);
4313
4314        let (kind, return_type) = self.analyze_member_call(
4315            type_that_member_is_on,
4316            &field_name_str,
4317            ast_maybe_generic_arguments,
4318            ast_arguments,
4319            is_mutable,
4320            member_name,
4321        );
4322        let postfix = Postfix {
4323            node: resolved_node,
4324            ty: return_type,
4325            kind,
4326        };
4327
4328        let last_type = postfix.ty.clone();
4329        suffixes.push(postfix);
4330
4331        last_type
4332    }
4333
4334    fn is_compatible_initializer_list_target(
4335        &mut self,
4336        target_type: &TypeRef,
4337        initializer_element_type: &TypeRef,
4338    ) -> bool {
4339        match &*target_type.kind {
4340            TypeKind::VecStorage(vec_element_type, _vec_capacity) => self
4341                .types()
4342                .compatible_with(vec_element_type, initializer_element_type),
4343            TypeKind::FixedCapacityAndLengthArray(array_element_type, _array_capacity) => self
4344                .types()
4345                .compatible_with(array_element_type, initializer_element_type),
4346            _ => false,
4347        }
4348    }
4349
4350    fn is_compatible_initializer_pair_list_target(
4351        &mut self,
4352        target_type: &TypeRef,
4353        initializer_key_type: &TypeRef,
4354        initializer_value_type: &TypeRef,
4355    ) -> bool {
4356        match &*target_type.kind {
4357            TypeKind::MapStorage(storage_key, storage_value, _) => {
4358                self.types()
4359                    .compatible_with(initializer_key_type, storage_key)
4360                    && self
4361                    .types()
4362                    .compatible_with(initializer_value_type, storage_value)
4363            }
4364            _ => false,
4365        }
4366    }
4367
4368    fn types_did_not_match_try_late_coerce_expression(
4369        &mut self,
4370        expr: Expression,
4371        special_expected_type: &TypeRef,
4372        special_encountered_type: &TypeRef,
4373        node: &swamp_ast::Node,
4374    ) -> Expression {
4375        let expected_type = special_expected_type;
4376        let encountered_type = special_encountered_type;
4377        let encountered_is_optional = matches!(&*encountered_type.kind, TypeKind::Optional(_));
4378        if let TypeKind::Optional(expected_inner_type) = &*expected_type.kind {
4379            let inner_is_also_optional =
4380                matches!(&*expected_inner_type.kind, TypeKind::Optional(_));
4381            // If an optional is expected, we can wrap it if this type has the exact same
4382            // inner type
4383            assert!(!inner_is_also_optional);
4384
4385            // First make sure it is not already an optional type. we can not wrap an option with an option
4386            // TODO: Improve error handling
4387            if !encountered_is_optional {
4388                // good it isn't, lets see if they share inner types
4389                if self
4390                    .types()
4391                    .compatible_with(expected_inner_type, encountered_type)
4392                {
4393                    // they share inner types as well, lets wrap it up
4394                    let wrapped = self.create_expr(
4395                        ExpressionKind::Option(Option::from(Box::new(expr))),
4396                        expected_type.clone(),
4397                        node,
4398                    );
4399                    return wrapped;
4400                }
4401            }
4402        }
4403
4404        if matches!(&*expected_type.kind, &TypeKind::Bool) {
4405            // if it has a mut or immutable optional, then it works well to wrap it
4406            if encountered_is_optional {
4407                let bool_type = self.types().bool();
4408                let wrapped = self.create_expr(
4409                    ExpressionKind::CoerceOptionToBool(Box::from(expr)),
4410                    bool_type,
4411                    node,
4412                );
4413                return wrapped;
4414            }
4415        }
4416
4417        if matches!(
4418            (&*expected_type.kind, &*encountered_type.kind),
4419            (TypeKind::Codepoint, TypeKind::Int)
4420        ) {
4421            let coerced = self.create_expr(
4422                ExpressionKind::CoerceIntToChar(Box::new(expr)),
4423                expected_type.clone(),
4424                node,
4425            );
4426            return coerced;
4427        }
4428
4429        error!(?expected_type, ?encountered_type, "incompatible");
4430        self.create_err(
4431            ErrorKind::IncompatibleTypes {
4432                expected: expected_type.clone(),
4433                found: encountered_type.clone(),
4434            },
4435            node,
4436        )
4437    }
4438
4439    #[must_use]
4440    pub fn analyze_generic_parameter_usize(&self, generic_parameter: &GenericParameter) -> usize {
4441        let usize_node = generic_parameter.get_unsigned_int_node();
4442        let usize_str = self.get_text(usize_node);
4443        Self::str_to_unsigned_int(usize_str).unwrap() as usize
4444    }
4445
4446    #[must_use]
4447    pub fn analyze_generic_parameter_usize_tuple(
4448        &self,
4449        generic_parameter: &GenericParameter,
4450    ) -> (usize, usize) {
4451        let (first, second) = generic_parameter.get_unsigned_int_tuple_nodes();
4452        let first_str = self.get_text(first);
4453        let second_str = self.get_text(second);
4454        let first_value = Self::str_to_unsigned_int(first_str).unwrap() as usize;
4455        let second_value = Self::str_to_unsigned_int(second_str).unwrap() as usize;
4456
4457        (first_value, second_value)
4458    }
4459
4460    pub fn analyze_special_named_type(
4461        &mut self,
4462        path: &[String],
4463        name: &str,
4464        ast_generic_parameters: &[GenericParameter],
4465    ) -> Option<TypeRef> {
4466        let converted_type = match name {
4467            "String" => {
4468                if ast_generic_parameters.len() == 1 {
4469                    let fixed_size =
4470                        self.analyze_generic_parameter_usize(&ast_generic_parameters[0]);
4471                    let new_type = self.shared.state.types.string_storage(fixed_size);
4472                    let default_node = swamp_ast::Node::default();
4473                    self.add_default_functions(&new_type, &default_node);
4474                    new_type
4475                } else {
4476                    return None;
4477                }
4478            }
4479            "Vec" => {
4480                if ast_generic_parameters.len() == 1 {
4481                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type());
4482                    let vec_type = self.shared.state.types.dynamic_vec_view(&element_type);
4483                    // Generate default functions for the new dynamic vec view type
4484                    let default_node = swamp_ast::Node::default();
4485                    self.add_default_functions(&vec_type, &default_node);
4486                    vec_type
4487                } else if ast_generic_parameters.len() == 2 {
4488                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type());
4489                    let fixed_size =
4490                        self.analyze_generic_parameter_usize(&ast_generic_parameters[1]);
4491                    let vec_storage_type = self
4492                        .shared
4493                        .state
4494                        .types
4495                        .vec_storage(&element_type, fixed_size);
4496                    // Generate default functions for the new vec storage type
4497                    let default_node = swamp_ast::Node::default();
4498                    self.add_default_functions(&vec_storage_type, &default_node);
4499                    vec_storage_type
4500                } else {
4501                    panic!("todo: make this into an error")
4502                }
4503            }
4504            "Stack" => {
4505                if ast_generic_parameters.len() == 1 {
4506                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type());
4507                    let stack_view_type = self.shared.state.types.stack_view(&element_type);
4508                    // Generate default functions for the new stack view type
4509                    let default_node = swamp_ast::Node::default();
4510                    self.add_default_functions(&stack_view_type, &default_node);
4511                    stack_view_type
4512                } else if ast_generic_parameters.len() == 2 {
4513                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type());
4514                    let fixed_size =
4515                        self.analyze_generic_parameter_usize(&ast_generic_parameters[1]);
4516                    let stack_storage_type = self
4517                        .shared
4518                        .state
4519                        .types
4520                        .stack_storage(&element_type, fixed_size);
4521                    // Generate default functions for the new stack storage type
4522                    let default_node = swamp_ast::Node::default();
4523                    self.add_default_functions(&stack_storage_type, &default_node);
4524                    stack_storage_type
4525                } else {
4526                    panic!("todo: make this into an error")
4527                }
4528            }
4529            "Queue" => {
4530                if ast_generic_parameters.len() == 1 {
4531                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type());
4532                    let queue_view_type = self.shared.state.types.queue_view(&element_type);
4533                    // Generate default functions for the new queue view type
4534                    let default_node = swamp_ast::Node::default();
4535                    self.add_default_functions(&queue_view_type, &default_node);
4536                    queue_view_type
4537                } else if ast_generic_parameters.len() == 2 {
4538                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type());
4539                    let fixed_size =
4540                        self.analyze_generic_parameter_usize(&ast_generic_parameters[1]);
4541                    let queue_storage_type = self
4542                        .shared
4543                        .state
4544                        .types
4545                        .queue_storage(&element_type, fixed_size);
4546                    // Generate default functions for the new queue storage type
4547                    let default_node = swamp_ast::Node::default();
4548                    self.add_default_functions(&queue_storage_type, &default_node);
4549                    queue_storage_type
4550                } else {
4551                    panic!("todo: make this into an error")
4552                }
4553            }
4554            "Sparse" => {
4555                if ast_generic_parameters.len() == 1 {
4556                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type());
4557                    let sparse_view_type = self.shared.state.types.sparse_view(&element_type);
4558                    // Generate default functions for the new sparse view type
4559                    let default_node = swamp_ast::Node::default();
4560                    self.add_default_functions(&sparse_view_type, &default_node);
4561                    sparse_view_type
4562                } else if ast_generic_parameters.len() == 2 {
4563                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type());
4564                    let fixed_size =
4565                        self.analyze_generic_parameter_usize(&ast_generic_parameters[1]);
4566                    let sparse_storage_type = self
4567                        .shared
4568                        .state
4569                        .types
4570                        .sparse_storage(&element_type, fixed_size);
4571                    // Generate default functions for the new sparse storage type
4572                    let default_node = swamp_ast::Node::default();
4573                    self.add_default_functions(&sparse_storage_type, &default_node);
4574                    sparse_storage_type
4575                } else {
4576                    panic!("todo: make this into an error")
4577                }
4578            }
4579
4580            "Grid" => {
4581                if ast_generic_parameters.len() == 1 {
4582                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type());
4583                    let grid_view_type = self.shared.state.types.grid_view(&element_type);
4584                    // Generate default functions for the new grid view type
4585                    let default_node = swamp_ast::Node::default();
4586                    self.add_default_functions(&grid_view_type, &default_node);
4587                    grid_view_type
4588                } else if ast_generic_parameters.len() == 2 {
4589                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type());
4590                    let (width, height) =
4591                        self.analyze_generic_parameter_usize_tuple(&ast_generic_parameters[1]);
4592                    let grid_storage_type =
4593                        self.shared
4594                            .state
4595                            .types
4596                            .grid_storage(&element_type, width, height);
4597                    // Generate default functions for the new grid storage type
4598                    let default_node = swamp_ast::Node::default();
4599                    self.add_default_functions(&grid_storage_type, &default_node);
4600                    grid_storage_type
4601                } else {
4602                    panic!("todo: make this into an error")
4603                }
4604            }
4605
4606            _ => return None,
4607        };
4608
4609        Some(converted_type)
4610    }
4611
4612    fn special_static_member(
4613        &self,
4614        type_identifier: &QualifiedTypeIdentifier,
4615        member_name_node: &swamp_ast::Node,
4616    ) -> Option<Function> {
4617        if type_identifier.generic_params.is_empty() {
4618            return None;
4619        }
4620
4621        if type_identifier.module_path.is_some() {
4622            return None;
4623        }
4624
4625        let member_name = self.get_text(member_name_node);
4626        let name = self.get_text(&type_identifier.name.0);
4627
4628        match name {
4629            "Stack" => None,
4630            _ => None,
4631        }
4632    }
4633}