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