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