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