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::{Type, 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, context)
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                        _ => return self.create_err(ErrorKind::ExpectedTupleType, &chain.base.node),
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        if *resulting_type.kind == TypeKind::Unit {
2660            return self.create_err(ErrorKind::VariableTypeMustBeBlittable(resulting_type), &var.name);
2661        }
2662        assert_ne!(&*resulting_type.kind, &TypeKind::Unit);
2663        let kind = ExpressionKind::VariableDefinition(var_ref, Box::from(resolved_source));
2664
2665        let unit_type = self.shared.state.types.unit();
2666
2667        self.create_expr(kind, unit_type, &var.name)
2668    }
2669
2670    fn add_location_item(
2671        &mut self,
2672        vec: &mut Vec<LocationAccess>,
2673        kind: LocationAccessKind,
2674        ty: TypeRef,
2675        ast_node: &swamp_ast::Node,
2676    ) {
2677        let resolved_node = self.to_node(ast_node);
2678        let postfix = LocationAccess {
2679            node: resolved_node,
2680            ty,
2681            kind,
2682        };
2683
2684        vec.push(postfix);
2685    }
2686
2687    fn extract_single_intrinsic_call(
2688        body: &Expression,
2689    ) -> Option<(IntrinsicFunction, Vec<ArgumentExpression>)> {
2690        if let ExpressionKind::Block(expressions) = &body.kind {
2691            let first_kind = &expressions[0].kind;
2692            if let ExpressionKind::IntrinsicCallEx(intrinsic_fn, args) = &first_kind {
2693                return Some((intrinsic_fn.clone(), args.clone()));
2694            }
2695        }
2696        None
2697    }
2698
2699    #[allow(clippy::too_many_lines)]
2700    fn analyze_chain_to_location(
2701        &mut self,
2702        chain: &swamp_ast::PostfixChain,
2703        context: &TypeContext,
2704        location_side: LocationSide,
2705    ) -> SingleLocationExpression {
2706        let mut items = Vec::new();
2707
2708        let nothing_context = TypeContext::new(None, true);
2709
2710        let base_expr = self.analyze_expression(&chain.base, &nothing_context);
2711        let ExpressionKind::VariableAccess(start_variable) = base_expr.kind else {
2712            self.add_err(ErrorKind::NotValidLocationStartingPoint, &chain.base.node);
2713            let unit_type = self.types().unit();
2714            let err_variable = Variable {
2715                name: Default::default(),
2716                assigned_name: String::new(),
2717                resolved_type: unit_type,
2718                mutable_node: None,
2719                variable_type: VariableType::Local,
2720                scope_index: 0,
2721                variable_index: 0,
2722                unique_id_within_function: 0,
2723                virtual_register: 0,
2724                is_unused: false,
2725            };
2726            return SingleLocationExpression {
2727                kind: MutableReferenceKind::MutVariableRef,
2728                node: self.to_node(&chain.base.node),
2729                ty: self.shared.state.types.unit(),
2730                starting_variable: VariableRef::from(err_variable),
2731                access_chain: vec![],
2732            };
2733        };
2734
2735        if !start_variable.is_mutable() {
2736            self.add_err(ErrorKind::VariableIsNotMutable, &chain.base.node);
2737
2738            let unit_type = self.types().unit();
2739            let err_variable = Variable {
2740                name: Default::default(),
2741                assigned_name: String::new(),
2742                resolved_type: unit_type,
2743                mutable_node: None,
2744                variable_type: VariableType::Local,
2745                scope_index: 0,
2746                variable_index: 0,
2747                unique_id_within_function: 0,
2748                virtual_register: 0,
2749                is_unused: false,
2750            };
2751            return SingleLocationExpression {
2752                kind: MutableReferenceKind::MutVariableRef,
2753                node: self.to_node(&chain.base.node),
2754                ty: self.shared.state.types.unit(),
2755                starting_variable: VariableRef::from(err_variable),
2756                access_chain: vec![],
2757            };
2758        }
2759
2760        let mut ty = start_variable.resolved_type.clone();
2761        for (i, item) in chain.postfixes.iter().enumerate() {
2762            let is_absolute_last_in_chain = i == chain.postfixes.len() - 1;
2763            match &item {
2764                swamp_ast::Postfix::FieldAccess(field_name_node) => {
2765                    //let field_name_resolved = self.to_node(field_name_node)
2766                    let (struct_type_ref, index, return_type) =
2767                        self.analyze_struct_field(field_name_node, &ty);
2768
2769                    self.add_location_item(
2770                        &mut items,
2771                        LocationAccessKind::FieldIndex(struct_type_ref.clone(), index),
2772                        return_type.clone(),
2773                        field_name_node,
2774                    );
2775
2776                    ty = return_type.clone();
2777                }
2778                swamp_ast::Postfix::SubscriptTuple(x_expr, y_expr) => match &*ty.kind {
2779                    TypeKind::GridView(element_type)
2780                    | TypeKind::GridStorage(element_type, _, _) => {
2781                        let int_type = self.types().int();
2782                        let unsigned_int_context = TypeContext::new_argument(&int_type, true);
2783                        let unsigned_int_x_expr =
2784                            self.analyze_expression(x_expr, &unsigned_int_context);
2785
2786                        let unsigned_int_y_expr =
2787                            self.analyze_expression(y_expr, &unsigned_int_context);
2788
2789                        let grid_type = GridType {
2790                            element: element_type.clone(),
2791                        };
2792
2793                        self.add_location_item(
2794                            &mut items,
2795                            LocationAccessKind::GridSubscript(
2796                                grid_type,
2797                                unsigned_int_x_expr,
2798                                unsigned_int_y_expr,
2799                            ),
2800                            element_type.clone(),
2801                            &x_expr.node,
2802                        );
2803
2804                        ty = element_type.clone();
2805                    }
2806                    _ => {
2807                        self.add_err_resolved(ErrorKind::CanNotSubscriptWithThatType, &base_expr.node);
2808
2809                        return SingleLocationExpression {
2810                            kind: MutableReferenceKind::MutVariableRef,
2811                            node: Default::default(),
2812                            ty,
2813                            starting_variable: Rc::new(Variable {
2814                                name: Default::default(),
2815                                assigned_name: String::new(),
2816                                resolved_type: Rc::new(Type {
2817                                    id: TypeId::new(0),
2818                                    flags: Default::default(),
2819                                    kind: Rc::new(TypeKind::Byte),
2820                                }),
2821                                mutable_node: None,
2822                                variable_type: VariableType::Local,
2823                                scope_index: 0,
2824                                variable_index: 0,
2825                                unique_id_within_function: 0,
2826                                virtual_register: 0,
2827                                is_unused: false,
2828                            }),
2829                            access_chain: vec![],
2830                        };
2831                    }
2832                },
2833                swamp_ast::Postfix::Subscript(ast_key_expression) => {
2834                    let underlying = &ty.kind;
2835                    match &**underlying {
2836                        TypeKind::SliceView(element_type)
2837                        | TypeKind::StackStorage(element_type, _)
2838                        | TypeKind::StackView(element_type)
2839                        | TypeKind::VecStorage(element_type, _)
2840                        | TypeKind::DynamicLengthVecView(element_type)
2841                        | TypeKind::FixedCapacityAndLengthArray(element_type, _) => {
2842                            let int_type = self.types().int();
2843                            let unsigned_int_context = TypeContext::new_argument(&int_type, false);
2844                            let unsigned_int_expr =
2845                                self.analyze_expression(ast_key_expression, &unsigned_int_context);
2846
2847                            let slice_type = SliceViewType {
2848                                element: element_type.clone(),
2849                            };
2850
2851                            self.add_location_item(
2852                                &mut items,
2853                                LocationAccessKind::SliceViewSubscript(
2854                                    slice_type,
2855                                    unsigned_int_expr,
2856                                ),
2857                                element_type.clone(),
2858                                &ast_key_expression.node,
2859                            );
2860
2861                            ty = element_type.clone();
2862                        }
2863                        TypeKind::SparseView(element_type)
2864                        | TypeKind::SparseStorage(element_type, _) => {
2865                            let int_type = self.types().int();
2866                            let unsigned_int_context = TypeContext::new_argument(&int_type, false);
2867                            let unsigned_int_expr =
2868                                self.analyze_expression(ast_key_expression, &unsigned_int_context);
2869
2870                            let slice_type = SparseType {
2871                                element: element_type.clone(),
2872                            };
2873
2874                            self.add_location_item(
2875                                &mut items,
2876                                LocationAccessKind::SparseSubscript(slice_type, unsigned_int_expr),
2877                                element_type.clone(),
2878                                &ast_key_expression.node,
2879                            );
2880
2881                            ty = element_type.clone();
2882                        }
2883                        TypeKind::MapStorage(key_type, value_type, ..)
2884                        | TypeKind::DynamicLengthMapView(key_type, value_type) => {
2885                            let key_index_context = TypeContext::new_argument(key_type, false);
2886                            let key_expr =
2887                                self.analyze_expression(ast_key_expression, &key_index_context);
2888
2889                            let map_like_type = MapType {
2890                                key: key_type.clone(),
2891                                value: value_type.clone(),
2892                            };
2893
2894                            match location_side {
2895                                LocationSide::Lhs => {
2896                                    // Only if it is the absolute last subscript in the chain that we should
2897                                    // create a new map entry, otherwise we should just lookup an existing entry and get the
2898                                    // address to it.
2899                                    let access_kind = if is_absolute_last_in_chain {
2900                                        LocationAccessKind::MapSubscriptCreateIfNeeded(
2901                                            map_like_type,
2902                                            key_expr,
2903                                        )
2904                                    } else {
2905                                        LocationAccessKind::MapSubscriptMustExist(
2906                                            map_like_type,
2907                                            key_expr,
2908                                        )
2909                                    };
2910
2911                                    self.add_location_item(
2912                                        &mut items,
2913                                        access_kind,
2914                                        value_type.clone(),
2915                                        &ast_key_expression.node,
2916                                    );
2917                                }
2918                                LocationSide::Mutable | LocationSide::Rhs => {
2919                                    self.add_location_item(
2920                                        &mut items,
2921                                        LocationAccessKind::MapSubscriptMustExist(
2922                                            map_like_type,
2923                                            key_expr,
2924                                        ),
2925                                        value_type.clone(),
2926                                        &ast_key_expression.node,
2927                                    );
2928                                }
2929                            }
2930                            ty = value_type.clone();
2931                        }
2932
2933                        _ => {
2934                            self.add_err_resolved(ErrorKind::CanNotSubscriptWithThatType, &base_expr.node);
2935
2936                            return SingleLocationExpression {
2937                                kind: MutableReferenceKind::MutVariableRef,
2938                                node: Default::default(),
2939                                ty,
2940                                starting_variable: Rc::new(Variable {
2941                                    name: Default::default(),
2942                                    assigned_name: String::new(),
2943                                    resolved_type: Rc::new(Type {
2944                                        id: TypeId::new(0),
2945                                        flags: Default::default(),
2946                                        kind: Rc::new(TypeKind::Byte),
2947                                    }),
2948                                    mutable_node: None,
2949                                    variable_type: VariableType::Local,
2950                                    scope_index: 0,
2951                                    variable_index: 0,
2952                                    unique_id_within_function: 0,
2953                                    virtual_register: 0,
2954                                    is_unused: false,
2955                                }),
2956                                access_chain: vec![],
2957                            };
2958                        }
2959                    }
2960                }
2961
2962                swamp_ast::Postfix::MemberCall(node, _generic_arguments, _regular_args) => {
2963                    return SingleLocationExpression {
2964                        kind: MutableReferenceKind::MutVariableRef,
2965                        node: self.to_node(node),
2966                        ty: self.shared.state.types.unit(),
2967                        starting_variable: start_variable,
2968                        access_chain: vec![],
2969                    };
2970                }
2971                /*
2972                swamp_ast::Postfix::AdvancedFunctionCall(_, node, ..) => {
2973                    return Err(self.create_err(ErrorKind::CallsCanNotBePartOfChain, node));
2974                }
2975
2976                 */
2977                swamp_ast::Postfix::FunctionCall(node, _generic_arguments, _regular_args) => {
2978                    return SingleLocationExpression {
2979                        kind: MutableReferenceKind::MutVariableRef,
2980                        node: self.to_node(node),
2981                        ty: self.shared.state.types.unit(),
2982                        starting_variable: start_variable,
2983                        access_chain: vec![],
2984                    };
2985                }
2986                swamp_ast::Postfix::OptionalChainingOperator(node) => {
2987                    return SingleLocationExpression {
2988                        kind: MutableReferenceKind::MutVariableRef,
2989                        node: self.to_node(node),
2990                        ty: self.shared.state.types.unit(),
2991                        starting_variable: start_variable,
2992                        access_chain: vec![],
2993                    };
2994                }
2995            }
2996        }
2997
2998        if let Some(found_expected_type) = context.expected_type
2999            && !self.types().compatible_with(found_expected_type, &ty) {
3000            self.add_err(
3001                ErrorKind::IncompatibleTypes {
3002                    expected: found_expected_type.clone(),
3003                    found: ty.clone(),
3004                },
3005                &chain.base.node,
3006            );
3007        }
3008
3009        SingleLocationExpression {
3010            kind: MutableReferenceKind::MutVariableRef,
3011            node: self.to_node(&chain.base.node),
3012            ty,
3013            starting_variable: start_variable,
3014            access_chain: items,
3015        }
3016    }
3017
3018    fn analyze_to_location(
3019        &mut self,
3020        expr: &swamp_ast::Expression,
3021        context: &TypeContext,
3022        location_type: LocationSide,
3023    ) -> SingleLocationExpression {
3024        match &expr.kind {
3025            swamp_ast::ExpressionKind::PostfixChain(chain) => {
3026                self.analyze_chain_to_location(chain, context, location_type)
3027            }
3028            swamp_ast::ExpressionKind::VariableReference(variable) => {
3029                let var = self.find_variable(variable);
3030                if !var.is_mutable() {
3031                    self.add_err(ErrorKind::VariableIsNotMutable, &expr.node);
3032                }
3033
3034                SingleLocationExpression {
3035                    kind: MutableReferenceKind::MutVariableRef,
3036                    node: self.to_node(&variable.name),
3037                    ty: var.resolved_type.clone(),
3038                    starting_variable: var,
3039                    access_chain: vec![],
3040                }
3041            }
3042            swamp_ast::ExpressionKind::IdentifierReference(qualified_identifier) => {
3043                let generated_var = swamp_ast::Variable {
3044                    name: qualified_identifier.name.clone(),
3045                    is_mutable: None,
3046                };
3047                let var = self.find_variable(&generated_var);
3048                if !var.is_mutable() {
3049                    self.add_err(ErrorKind::VariableIsNotMutable, &expr.node);
3050                }
3051                SingleLocationExpression {
3052                    kind: MutableReferenceKind::MutVariableRef,
3053                    node: self.to_node(&generated_var.name),
3054                    ty: var.resolved_type.clone(),
3055                    starting_variable: var,
3056                    access_chain: vec![],
3057                }
3058            }
3059            _ => {
3060                self.add_err(ErrorKind::NotValidLocationStartingPoint, &expr.node);
3061                let unit_type = self.types().unit();
3062                SingleLocationExpression {
3063                    kind: MutableReferenceKind::MutVariableRef,
3064                    node: self.to_node(&expr.node),
3065                    ty: unit_type.clone(),
3066                    starting_variable: Rc::new(Variable {
3067                        name: Default::default(),
3068                        assigned_name: String::new(),
3069                        resolved_type: unit_type,
3070                        mutable_node: None,
3071                        variable_type: VariableType::Local,
3072                        scope_index: 0,
3073                        variable_index: 0,
3074                        unique_id_within_function: 0,
3075                        virtual_register: 0,
3076                        is_unused: false,
3077                    }),
3078                    access_chain: vec![],
3079                }
3080            }
3081        }
3082    }
3083
3084    fn analyze_expression_for_assignment_compound(
3085        &mut self,
3086        target_expression: &swamp_ast::Expression,
3087        ast_source_expression: &swamp_ast::Expression,
3088    ) -> (TargetAssignmentLocation, Expression) {
3089        let any_argument_context = TypeContext::new_anything_argument(true);
3090        let source_expr = self.analyze_expression(ast_source_expression, &any_argument_context);
3091        let source_expr_type_context = TypeContext::new_argument(&source_expr.ty, true);
3092
3093        let resolved_location = TargetAssignmentLocation(self.analyze_to_location(
3094            target_expression,
3095            &source_expr_type_context,
3096            LocationSide::Rhs,
3097        ));
3098
3099        (resolved_location, source_expr)
3100    }
3101
3102    /*
3103    fn try_convert_for_assignment(
3104        &mut self,
3105        expr: &Expression,
3106        target_type: &TypeRef,
3107        ast_node: &swamp_ast::Expression,
3108    ) -> Result<Option<Expression>, Error> {
3109        match (target_type, &expr.ty) {
3110            // Conversion cases that require transformation
3111            (TypeKind::VecStorage(target_elem, capacity), TypeKind::FixedSlice(source_elem, _)) => {
3112                // Create conversion with checks
3113                // ...
3114            }
3115
3116            (TypeKind::String, TypeKind::Int) => {
3117                // Create int-to-string conversion
3118                // ...
3119            }
3120
3121            // No conversion possible
3122            _ => Ok(None),
3123        }
3124    }
3125
3126     */
3127
3128    fn analyze_expression_for_assignment_with_target_type(
3129        &mut self,
3130        target_type: &TypeRef,
3131        ast_source_expression: &swamp_ast::Expression,
3132    ) -> Expression {
3133        let base_context = TypeContext::new_argument(target_type, true);
3134        let source_expr = self.analyze_expression(ast_source_expression, &base_context);
3135
3136        let final_expr = if self.types().compatible_with(target_type, &source_expr.ty) {
3137            source_expr
3138        } else {
3139            let source_type = source_expr.ty.clone();
3140            self.types_did_not_match_try_late_coerce_expression(
3141                source_expr,
3142                target_type,
3143                &source_type,
3144                &ast_source_expression.node,
3145            )
3146        };
3147
3148        let assignment_mode = self.check_assignment_mode(true, &final_expr, target_type); // TODO: Fill in correct lhs_is_mutable
3149
3150        self.check_mutable_assignment(assignment_mode, &final_expr.node);
3151
3152        final_expr
3153    }
3154
3155    fn analyze_expression_for_assignment(
3156        &mut self,
3157        ast_target_location_expression: &swamp_ast::Expression,
3158        ast_source_expression: &swamp_ast::Expression,
3159    ) -> (TargetAssignmentLocation, Expression) {
3160        let any_argument_context = TypeContext::new_anything_argument(true);
3161        let resolved_location = self.analyze_to_location(
3162            ast_target_location_expression,
3163            &any_argument_context,
3164            LocationSide::Lhs,
3165        );
3166
3167        let target_type = resolved_location.ty.clone();
3168        let mut_type = target_type; // Mutable references now use the same type
3169        let mut_location = TargetAssignmentLocation(resolved_location);
3170
3171        let final_expr = self
3172            .analyze_expression_for_assignment_with_target_type(&mut_type, ast_source_expression);
3173
3174        (mut_location, final_expr)
3175    }
3176
3177    fn analyze_assignment_compound(
3178        &mut self,
3179        target_expression: &swamp_ast::Expression,
3180        ast_op: &swamp_ast::CompoundOperator,
3181        ast_source_expression: &swamp_ast::Expression,
3182    ) -> Expression {
3183        let resolved_op = self.analyze_compound_operator(ast_op);
3184
3185        let (resolved_location, source_expr) = self
3186            .analyze_expression_for_assignment_compound(target_expression, ast_source_expression);
3187
3188        let kind = ExpressionKind::CompoundAssignment(
3189            resolved_location,
3190            resolved_op.kind,
3191            Box::from(source_expr),
3192        );
3193
3194        let unit_type = self.shared.state.types.unit();
3195
3196        self.create_expr(kind, unit_type, &target_expression.node)
3197    }
3198
3199    fn analyze_assignment_mode(lhs: SingleLocationExpression) {}
3200
3201    fn analyze_assignment(
3202        &mut self,
3203        target_location: &swamp_ast::Expression,
3204        ast_source_expression: &swamp_ast::Expression,
3205    ) -> Expression {
3206        let (mut_location, source_expr) =
3207            self.analyze_expression_for_assignment(target_location, ast_source_expression);
3208        let kind = ExpressionKind::Assignment(Box::from(mut_location), Box::from(source_expr));
3209        let unit_type = self.shared.state.types.unit();
3210
3211        // Assignments are always of type Unit
3212
3213        self.create_expr(kind, unit_type, &target_location.node)
3214    }
3215
3216    #[must_use]
3217    pub const fn create_expr(
3218        &self,
3219        kind: ExpressionKind,
3220        ty: TypeRef,
3221        ast_node: &swamp_ast::Node,
3222    ) -> Expression {
3223        //info!(%ty, ?kind, "create_expr()");
3224        Expression {
3225            kind,
3226            ty,
3227            node: self.to_node(ast_node),
3228        }
3229    }
3230
3231    fn analyze_destructuring(
3232        &mut self,
3233        node: &swamp_ast::Node,
3234        target_ast_variables: &[swamp_ast::Variable],
3235        tuple_expression: &swamp_ast::Expression,
3236    ) -> Expression {
3237        let any_context = TypeContext::new_anything_argument(true);
3238        let tuple_resolved = self.analyze_expression(tuple_expression, &any_context);
3239        let tuple_expr_type = &tuple_resolved.ty;
3240        let unit = self.types().unit();
3241
3242        let mut variable_refs = Vec::new();
3243        if let TypeKind::Tuple(tuple) = &*tuple_expr_type.kind {
3244            if target_ast_variables.len() > tuple.len() {
3245                return self.create_err(ErrorKind::TooManyDestructureVariables, node);
3246            }
3247            for (ast_variable, tuple_type) in target_ast_variables.iter().zip(tuple.clone()) {
3248                let variable_ref = self.create_local_variable(
3249                    &ast_variable.name,
3250                    ast_variable.is_mutable.as_ref(),
3251                    &tuple_type,
3252                    true,
3253                );
3254                variable_refs.push(variable_ref);
3255            }
3256            let expr_kind = ExpressionKind::TupleDestructuring(
3257                variable_refs,
3258                tuple_expr_type.clone(),
3259                Box::from(tuple_resolved),
3260            );
3261
3262            self.create_expr(expr_kind, unit, node)
3263        } else {
3264            self.create_err(ErrorKind::CanNotDestructure, node)
3265        }
3266    }
3267
3268    fn analyze_normal_member_call(
3269        &mut self,
3270        type_that_member_is_on: &TypeRef,
3271        found_function: &FunctionRef,
3272        generic_arguments: Vec<TypeRef>,
3273        ast_arguments: &[swamp_ast::Expression],
3274        is_mutable: bool,
3275        node: &swamp_ast::Node,
3276    ) -> Signature {
3277        let resolved_node = self.to_node(node);
3278        // TODO:
3279
3280        found_function.signature().clone()
3281    }
3282
3283    fn queue_member_signature(
3284        &mut self,
3285        self_type: &TypeRef,
3286        key_type: Option<&TypeRef>,
3287        element_type: &TypeRef,
3288        field_name_str: &str,
3289        lambda_variable_count: usize,
3290        node: &swamp_ast::Node,
3291    ) -> Option<(IntrinsicFunction, Signature)> {
3292        let self_type_param = TypeForParameter {
3293            name: "self".to_string(),
3294            resolved_type: self_type.clone(),
3295            is_mutable: false,
3296            node: None,
3297        };
3298        let self_mutable_type_param = TypeForParameter {
3299            name: "self".to_string(),
3300            resolved_type: self_type.clone(),
3301            is_mutable: true,
3302            node: None,
3303        };
3304        let intrinsic_and_signature = match field_name_str {
3305            "enqueue" => (
3306                IntrinsicFunction::VecPush,
3307                Signature {
3308                    parameters: vec![
3309                        self_mutable_type_param,
3310                        TypeForParameter {
3311                            name: "element".to_string(),
3312                            resolved_type: element_type.clone(),
3313                            is_mutable: false,
3314                            node: None,
3315                        },
3316                    ],
3317                    return_type: self.types().unit(),
3318                },
3319            ),
3320            "dequeue" => (
3321                IntrinsicFunction::VecRemoveFirstIndexGetValue,
3322                Signature {
3323                    parameters: vec![self_mutable_type_param],
3324                    return_type: element_type.clone(),
3325                },
3326            ),
3327            _ => {
3328                self.slice_member_signature(
3329                    self_type,
3330                    key_type,
3331                    element_type,
3332                    field_name_str,
3333                    lambda_variable_count,
3334                    node,
3335                )
3336            }?,
3337        };
3338
3339        Some(intrinsic_and_signature)
3340    }
3341
3342    fn sparse_member_signature(
3343        &mut self,
3344        self_type: &TypeRef,
3345        element_type: &TypeRef,
3346        field_name_str: &str,
3347        lambda_variable_count: usize,
3348        node: &swamp_ast::Node,
3349    ) -> Option<(IntrinsicFunction, Signature)> {
3350        let key_type = self.types().int(); // TODO: SparseID
3351
3352        let self_type_param = TypeForParameter {
3353            name: "self".to_string(),
3354            resolved_type: self_type.clone(),
3355            is_mutable: false,
3356            node: None,
3357        };
3358        let self_mutable_type_param = TypeForParameter {
3359            name: "self".to_string(),
3360            resolved_type: self_type.clone(),
3361            is_mutable: true,
3362            node: None,
3363        };
3364        let intrinsic_and_signature = match field_name_str {
3365            "add" => (
3366                IntrinsicFunction::SparseAdd,
3367                Signature {
3368                    parameters: vec![
3369                        self_mutable_type_param,
3370                        TypeForParameter {
3371                            name: "element".to_string(),
3372                            resolved_type: element_type.clone(),
3373                            is_mutable: false,
3374                            node: None,
3375                        },
3376                    ],
3377                    return_type: self.types().int(),
3378                },
3379            ),
3380            "remove" => (
3381                IntrinsicFunction::SparseRemove,
3382                Signature {
3383                    parameters: vec![
3384                        self_mutable_type_param,
3385                        TypeForParameter {
3386                            name: "key".to_string(),
3387                            resolved_type: key_type,
3388                            is_mutable: false,
3389                            node: None,
3390                        },
3391                    ],
3392                    return_type: self.types().unit(),
3393                },
3394            ),
3395            "is_alive" => (
3396                IntrinsicFunction::SparseIsAlive,
3397                Signature {
3398                    parameters: vec![
3399                        self_type_param,
3400                        TypeForParameter {
3401                            name: "element".to_string(),
3402                            resolved_type: element_type.clone(),
3403                            is_mutable: false,
3404                            node: None,
3405                        },
3406                    ],
3407                    return_type: self.types().bool(),
3408                },
3409            ),
3410
3411            _ => {
3412                self.slice_member_signature(
3413                    self_type,
3414                    Option::from(key_type).as_ref(),
3415                    element_type,
3416                    field_name_str,
3417                    lambda_variable_count,
3418                    node,
3419                )
3420            }?,
3421        };
3422        Some(intrinsic_and_signature)
3423    }
3424
3425    fn vec_member_signature(
3426        &mut self,
3427        self_type: &TypeRef,
3428        element_type: &TypeRef,
3429        field_name_str: &str,
3430        lambda_variable_count: usize,
3431        node: &swamp_ast::Node,
3432    ) -> Option<(IntrinsicFunction, Signature)> {
3433        let key_type = self.types().int();
3434        let self_type_param = TypeForParameter {
3435            name: "self".to_string(),
3436            resolved_type: self_type.clone(),
3437            is_mutable: false,
3438            node: None,
3439        };
3440        let self_mutable_type_param = TypeForParameter {
3441            name: "self".to_string(),
3442            resolved_type: self_type.clone(),
3443            is_mutable: true,
3444            node: None,
3445        };
3446        let intrinsic_and_signature = match field_name_str {
3447            "prepend" => (
3448                IntrinsicFunction::VecPush,
3449                Signature {
3450                    parameters: vec![
3451                        self_mutable_type_param,
3452                        TypeForParameter {
3453                            name: "element".to_string(),
3454                            resolved_type: element_type.clone(),
3455                            is_mutable: false,
3456                            node: None,
3457                        },
3458                    ],
3459                    return_type: self.types().unit(),
3460                },
3461            ),
3462            "push" => (
3463                IntrinsicFunction::VecPush,
3464                Signature {
3465                    parameters: vec![
3466                        self_mutable_type_param,
3467                        TypeForParameter {
3468                            name: "element".to_string(),
3469                            resolved_type: element_type.clone(),
3470                            is_mutable: false,
3471                            node: None,
3472                        },
3473                    ],
3474                    return_type: self.types().unit(),
3475                },
3476            ),
3477            "pop" => (
3478                IntrinsicFunction::VecPop,
3479                Signature {
3480                    parameters: vec![self_mutable_type_param],
3481                    return_type: element_type.clone(),
3482                },
3483            ),
3484
3485            "slice" => {
3486                let range_type = self.types().range_int();
3487                (
3488                    IntrinsicFunction::VecSlice,
3489                    Signature {
3490                        parameters: vec![self_type_param,
3491                                         TypeForParameter {
3492                                             name: "range".to_string(),
3493                                             resolved_type: range_type,
3494                                             is_mutable: false,
3495                                             node: None,
3496                                         }, ],
3497                        return_type: self_type.clone(),
3498                    },
3499                )
3500            }
3501
3502            _ => {
3503                self.slice_member_signature(
3504                    self_type,
3505                    Option::from(key_type).as_ref(),
3506                    element_type,
3507                    field_name_str,
3508                    lambda_variable_count,
3509                    node,
3510                )
3511            }?,
3512        };
3513        Some(intrinsic_and_signature)
3514    }
3515
3516    #[allow(clippy::unnecessary_wraps)]
3517    fn grid_member_signature(
3518        &mut self,
3519        self_type: &TypeRef,
3520        element_type: &TypeRef,
3521        field_name_str: &str,
3522        node: &swamp_ast::Node,
3523    ) -> Option<(IntrinsicFunction, Signature)> {
3524        let self_type_param = TypeForParameter {
3525            name: "self".to_string(),
3526            resolved_type: self_type.clone(),
3527            is_mutable: false,
3528            node: None,
3529        };
3530        let self_mutable_type_param = TypeForParameter {
3531            name: "self".to_string(),
3532            resolved_type: self_type.clone(),
3533            is_mutable: true,
3534            node: None,
3535        };
3536        let element_param = TypeForParameter {
3537            name: "element".to_string(),
3538            resolved_type: element_type.clone(),
3539            is_mutable: false,
3540            node: None,
3541        };
3542        let int_type = self.types().int();
3543
3544        let int_param = TypeForParameter {
3545            name: "x_or_y".to_string(),
3546            resolved_type: int_type.clone(),
3547            is_mutable: false,
3548            node: None,
3549        };
3550        let intrinsic_and_signature = match field_name_str {
3551            "set" => (
3552                IntrinsicFunction::GridSet,
3553                Signature {
3554                    parameters: vec![self_type_param, int_param.clone(), int_param, element_param],
3555                    return_type: self.types().unit(),
3556                },
3557            ),
3558
3559            "get" => (
3560                IntrinsicFunction::GridGet,
3561                Signature {
3562                    parameters: vec![self_type_param, int_param.clone(), int_param],
3563                    return_type: element_type.clone(),
3564                },
3565            ),
3566
3567            "width" => (
3568                IntrinsicFunction::GridWidth,
3569                Signature {
3570                    parameters: vec![self_type_param],
3571                    return_type: int_type,
3572                },
3573            ),
3574
3575            "height" => (
3576                IntrinsicFunction::GridHeight,
3577                Signature {
3578                    parameters: vec![self_type_param],
3579                    return_type: int_type,
3580                },
3581            ),
3582
3583            _ => panic!("unknown grid method {field_name_str}"),
3584        };
3585
3586        Some(intrinsic_and_signature)
3587    }
3588
3589    fn basic_collection_member_signature(
3590        &mut self,
3591        self_type: &TypeRef,
3592        field_name_str: &str,
3593        node: &swamp_ast::Node,
3594    ) -> Option<(IntrinsicFunction, Signature)> {
3595        let self_type_param = TypeForParameter {
3596            name: "self".to_string(),
3597            resolved_type: self_type.clone(),
3598            is_mutable: false,
3599            node: None,
3600        };
3601        let self_mut_type_param = TypeForParameter {
3602            name: "self".to_string(),
3603            resolved_type: self_type.clone(),
3604            is_mutable: true,
3605            node: None,
3606        };
3607        let intrinsic_and_signature = match field_name_str {
3608            "len" => {
3609                let signature = Signature {
3610                    parameters: vec![self_type_param],
3611                    return_type: self.types().int(),
3612                };
3613                (IntrinsicFunction::VecLen, signature)
3614            }
3615            "is_empty" => (
3616                IntrinsicFunction::VecIsEmpty,
3617                Signature {
3618                    parameters: vec![self_type_param],
3619                    return_type: self.types().bool(),
3620                },
3621            ),
3622            "clear" => {
3623                let signature = Signature {
3624                    parameters: vec![self_mut_type_param],
3625                    return_type: self.types().unit(),
3626                };
3627                (IntrinsicFunction::VecClear, signature)
3628            }
3629            "capacity" => {
3630                let signature = Signature {
3631                    parameters: vec![self_type_param],
3632                    return_type: self.types().int(),
3633                };
3634                (IntrinsicFunction::VecCapacity, signature)
3635            }
3636            _ => {
3637                self.add_err(ErrorKind::UnknownMemberFunction(self_type.clone()), node);
3638
3639                return None;
3640            }
3641        };
3642        Some(intrinsic_and_signature)
3643    }
3644    #[allow(clippy::too_many_lines)]
3645    fn codepoint_member_signature(
3646        &mut self,
3647        self_type: &TypeRef,
3648        key_type: Option<&TypeRef>,
3649        element_type: &TypeRef,
3650        field_name_str: &str,
3651        lambda_variable_count: usize,
3652        node: &swamp_ast::Node,
3653    ) -> Option<(IntrinsicFunction, Signature)> {
3654        let self_type_param = TypeForParameter {
3655            name: "self".to_string(),
3656            resolved_type: self_type.clone(),
3657            is_mutable: false,
3658            node: None,
3659        };
3660
3661        match field_name_str {
3662            "to_int" => Some((
3663                IntrinsicFunction::CodepointToInt,
3664                Signature {
3665                    parameters: vec![self_type_param],
3666                    return_type: self.types().int(),
3667                },
3668            )),
3669            _ => None,
3670        }
3671    }
3672
3673    #[allow(clippy::too_many_lines)]
3674    fn byte_member_signature(
3675        &mut self,
3676        self_type: &TypeRef,
3677        key_type: Option<&TypeRef>,
3678        element_type: &TypeRef,
3679        field_name_str: &str,
3680        lambda_variable_count: usize,
3681        node: &swamp_ast::Node,
3682    ) -> Option<(IntrinsicFunction, Signature)> {
3683        let self_type_param = TypeForParameter {
3684            name: "self".to_string(),
3685            resolved_type: self_type.clone(),
3686            is_mutable: false,
3687            node: None,
3688        };
3689
3690        match field_name_str {
3691            "to_int" => Some((
3692                IntrinsicFunction::ByteToInt,
3693                Signature {
3694                    parameters: vec![self_type_param],
3695                    return_type: self.types().int(),
3696                },
3697            )),
3698            _ => None,
3699        }
3700    }
3701
3702    #[allow(clippy::too_many_lines)]
3703    fn string_member_signature(
3704        &mut self,
3705        self_type: &TypeRef,
3706        key_type: Option<&TypeRef>,
3707        element_type: &TypeRef,
3708        field_name_str: &str,
3709        lambda_variable_count: usize,
3710        node: &swamp_ast::Node,
3711    ) -> Option<(IntrinsicFunction, Signature)> {
3712        self.vec_member_signature(
3713            self_type,
3714            element_type,
3715            field_name_str,
3716            lambda_variable_count,
3717            node,
3718        )
3719    }
3720
3721    #[allow(clippy::too_many_lines)]
3722    fn slice_member_signature(
3723        &mut self,
3724        self_type: &TypeRef,
3725        key_type: Option<&TypeRef>,
3726        element_type: &TypeRef,
3727        field_name_str: &str,
3728        lambda_variable_count: usize,
3729        node: &swamp_ast::Node,
3730    ) -> Option<(IntrinsicFunction, Signature)> {
3731        let slice_view_type = self.types().slice_view(&element_type.clone());
3732        let int_type = self.types().int();
3733        let self_type_param = TypeForParameter {
3734            name: "self".to_string(),
3735            resolved_type: slice_view_type.clone(),
3736            is_mutable: false,
3737            node: None,
3738        };
3739        let self_mut_type_param = TypeForParameter {
3740            name: "self".to_string(),
3741            resolved_type: slice_view_type,
3742            is_mutable: true,
3743            node: None,
3744        };
3745        let intrinsic_and_signature = match field_name_str {
3746            "for" => {
3747                let parameters = if lambda_variable_count == 2 {
3748                    vec![
3749                        TypeForParameter {
3750                            name: "key".to_string(),
3751                            resolved_type: key_type.unwrap().clone(),
3752                            is_mutable: false,
3753                            node: None,
3754                        },
3755                        TypeForParameter {
3756                            name: "element".to_string(),
3757                            resolved_type: element_type.clone(),
3758                            is_mutable: false,
3759                            node: None,
3760                        },
3761                    ]
3762                } else {
3763                    vec![TypeForParameter {
3764                        name: "element".to_string(),
3765                        resolved_type: element_type.clone(),
3766                        is_mutable: false,
3767                        node: None,
3768                    }]
3769                };
3770                let lambda_signature = Signature {
3771                    parameters,
3772                    return_type: self.types().unit(),
3773                };
3774                let lambda_function_type = self.types().function(lambda_signature);
3775                (
3776                    IntrinsicFunction::TransformerFor,
3777                    Signature {
3778                        parameters: vec![
3779                            self_type_param,
3780                            TypeForParameter {
3781                                name: "lambda".to_string(),
3782                                resolved_type: lambda_function_type,
3783                                is_mutable: false,
3784                                node: None,
3785                            },
3786                        ],
3787                        return_type: self.types().unit(), // VecFor is only used for side effects
3788                    },
3789                )
3790            }
3791            "while" => {
3792                let parameters = if lambda_variable_count == 2 {
3793                    vec![
3794                        TypeForParameter {
3795                            name: "key".to_string(),
3796                            resolved_type: key_type.unwrap().clone(),
3797                            is_mutable: false,
3798                            node: None,
3799                        },
3800                        TypeForParameter {
3801                            name: "element".to_string(),
3802                            resolved_type: element_type.clone(),
3803                            is_mutable: false,
3804                            node: None,
3805                        },
3806                    ]
3807                } else {
3808                    vec![TypeForParameter {
3809                        name: "element".to_string(),
3810                        resolved_type: element_type.clone(),
3811                        is_mutable: false,
3812                        node: None,
3813                    }]
3814                };
3815                let lambda_signature = Signature {
3816                    parameters,
3817                    return_type: self.types().bool(), // it returns if the while loop should continue
3818                };
3819                let lambda_function_type = self.types().function(lambda_signature);
3820                (
3821                    IntrinsicFunction::TransformerWhile,
3822                    Signature {
3823                        parameters: vec![
3824                            self_type_param,
3825                            TypeForParameter {
3826                                name: "lambda".to_string(),
3827                                resolved_type: lambda_function_type,
3828                                is_mutable: false,
3829                                node: None,
3830                            },
3831                        ],
3832                        return_type: self.types().unit(), // VecFor is only used for side effects
3833                    },
3834                )
3835            }
3836            "filter" => {
3837                let lambda_signature = Signature {
3838                    parameters: vec![TypeForParameter {
3839                        name: "element".to_string(),
3840                        resolved_type: element_type.clone(),
3841                        is_mutable: false,
3842                        node: None,
3843                    }],
3844                    return_type: self.types().bool(),
3845                };
3846                let lambda_function_type = self.types().function(lambda_signature);
3847                (
3848                    IntrinsicFunction::TransformerFilter,
3849                    Signature {
3850                        parameters: vec![
3851                            self_type_param,
3852                            TypeForParameter {
3853                                name: "lambda".to_string(),
3854                                resolved_type: lambda_function_type,
3855                                is_mutable: false,
3856                                node: None,
3857                            },
3858                        ],
3859                        return_type: self.shared.state.types.slice_view(&element_type.clone()),
3860                    },
3861                )
3862            }
3863            "find" => {
3864                let lambda_signature = Signature {
3865                    parameters: vec![TypeForParameter {
3866                        name: "element".to_string(),
3867                        resolved_type: element_type.clone(),
3868                        is_mutable: false,
3869                        node: None,
3870                    }],
3871                    return_type: self.types().bool(),
3872                };
3873                let lambda_function_type = self.types().function(lambda_signature);
3874                (
3875                    IntrinsicFunction::TransformerFind,
3876                    Signature {
3877                        parameters: vec![
3878                            self_type_param,
3879                            TypeForParameter {
3880                                name: "lambda".to_string(),
3881                                resolved_type: lambda_function_type,
3882                                is_mutable: false,
3883                                node: None,
3884                            },
3885                        ],
3886                        return_type: self.shared.state.types.optional(&element_type.clone()),
3887                    },
3888                )
3889            }
3890
3891            "remove" => {
3892                let signature = Signature {
3893                    parameters: vec![
3894                        self_mut_type_param,
3895                        TypeForParameter {
3896                            name: "index".to_string(),
3897                            resolved_type: int_type,
3898                            is_mutable: false,
3899                            node: None,
3900                        },
3901                    ],
3902                    return_type: self.types().unit(),
3903                };
3904                (IntrinsicFunction::VecRemoveIndex, signature)
3905            }
3906            _ => return self.basic_collection_member_signature(self_type, field_name_str, node),
3907        };
3908        Some(intrinsic_and_signature)
3909    }
3910
3911    #[allow(clippy::unnecessary_wraps, clippy::result_large_err)]
3912    fn map_member_signature(
3913        &mut self,
3914        self_type: &TypeRef,
3915        key_type: &TypeRef,
3916        value_type: &TypeRef,
3917        field_name_str: &str,
3918        node: &swamp_ast::Node,
3919    ) -> Option<(IntrinsicFunction, Signature)> {
3920        let self_type_param = TypeForParameter {
3921            name: "self".to_string(),
3922            resolved_type: self_type.clone(),
3923            is_mutable: false,
3924            node: None,
3925        };
3926
3927        let mutable_self_type_param = TypeForParameter {
3928            name: "self".to_string(),
3929            resolved_type: self_type.clone(),
3930            is_mutable: true,
3931            node: None,
3932        };
3933
3934        let intrinsic_and_signature = match field_name_str {
3935            "has" => (
3936                IntrinsicFunction::MapHas,
3937                Signature {
3938                    parameters: vec![
3939                        self_type_param,
3940                        TypeForParameter {
3941                            name: "key".to_string(),
3942                            resolved_type: key_type.clone(),
3943                            is_mutable: false,
3944                            node: None,
3945                        },
3946                    ],
3947                    return_type: self.types().bool(),
3948                },
3949            ),
3950            "remove" => (
3951                IntrinsicFunction::MapRemove,
3952                Signature {
3953                    parameters: vec![
3954                        mutable_self_type_param,
3955                        TypeForParameter {
3956                            name: "key".to_string(),
3957                            resolved_type: key_type.clone(),
3958                            is_mutable: false,
3959                            node: None,
3960                        },
3961                    ],
3962                    return_type: self.types().unit(),
3963                },
3964            ),
3965            "len" => (
3966                IntrinsicFunction::MapLen,
3967                Signature {
3968                    parameters: vec![self_type_param],
3969                    return_type: self.types().int(),
3970                },
3971            ),
3972            "capacity" => (
3973                IntrinsicFunction::MapCapacity,
3974                Signature {
3975                    parameters: vec![self_type_param],
3976                    return_type: self.types().int(),
3977                },
3978            ),
3979            "is_empty" => (
3980                IntrinsicFunction::MapIsEmpty,
3981                Signature {
3982                    parameters: vec![self_type_param],
3983                    return_type: self.types().bool(),
3984                },
3985            ),
3986            _ => todo!("unknown map member"),
3987        };
3988
3989        Some(intrinsic_and_signature)
3990    }
3991
3992    fn check_intrinsic_member_signature(
3993        &mut self,
3994        type_that_member_is_on: &TypeRef,
3995        field_name_str: &str,
3996        lambda_variables_count: usize,
3997        node: &swamp_ast::Node,
3998    ) -> Option<(IntrinsicFunction, Signature)> {
3999        let ty = type_that_member_is_on;
4000        let int_type = self.types().int();
4001        match &*ty.kind {
4002            TypeKind::GridStorage(element_type, ..) | TypeKind::GridView(element_type) => self
4003                .grid_member_signature(type_that_member_is_on, element_type, field_name_str, node),
4004            TypeKind::SparseStorage(element_type, ..) | TypeKind::SparseView(element_type) => self
4005                .sparse_member_signature(
4006                    type_that_member_is_on,
4007                    element_type,
4008                    field_name_str,
4009                    lambda_variables_count,
4010                    node,
4011                ),
4012            TypeKind::QueueStorage(element_type, ..) => self.queue_member_signature(
4013                type_that_member_is_on,
4014                None,
4015                element_type,
4016                field_name_str,
4017                lambda_variables_count,
4018                node,
4019            ),
4020            TypeKind::StackStorage(element_type, ..)
4021            | TypeKind::QueueStorage(element_type, ..)
4022            | TypeKind::VecStorage(element_type, ..)
4023            | TypeKind::DynamicLengthVecView(element_type) => self.vec_member_signature(
4024                type_that_member_is_on,
4025                element_type,
4026                field_name_str,
4027                lambda_variables_count,
4028                node,
4029            ),
4030            TypeKind::SliceView(element_type) => self.slice_member_signature(
4031                type_that_member_is_on,
4032                Some(&int_type),
4033                element_type,
4034                field_name_str,
4035                lambda_variables_count,
4036                node,
4037            ),
4038            TypeKind::Byte => {
4039                let element_type = self.shared.state.types.byte();
4040                self.byte_member_signature(
4041                    type_that_member_is_on,
4042                    Some(&int_type),
4043                    &element_type,
4044                    field_name_str,
4045                    lambda_variables_count,
4046                    node,
4047                )
4048            }
4049            TypeKind::Codepoint => {
4050                let element_type = self.shared.state.types.codepoint();
4051                self.codepoint_member_signature(
4052                    type_that_member_is_on,
4053                    Some(&int_type),
4054                    &element_type,
4055                    field_name_str,
4056                    lambda_variables_count,
4057                    node,
4058                )
4059            }
4060            TypeKind::String { .. } | TypeKind::StringStorage(..) => {
4061                let element_type = self.shared.state.types.byte();
4062                self.string_member_signature(
4063                    type_that_member_is_on,
4064                    Some(&int_type),
4065                    &element_type,
4066                    field_name_str,
4067                    lambda_variables_count,
4068                    node,
4069                )
4070            }
4071            TypeKind::DynamicLengthMapView(key, value) | TypeKind::MapStorage(key, value, _) => {
4072                self.map_member_signature(type_that_member_is_on, key, value, field_name_str, node)
4073            }
4074
4075            TypeKind::FixedCapacityAndLengthArray(element_type, _) => self.slice_member_signature(
4076                type_that_member_is_on,
4077                Some(&int_type),
4078                element_type,
4079                field_name_str,
4080                lambda_variables_count,
4081                node,
4082            ),
4083            _ => {
4084                self.add_err(
4085                    ErrorKind::UnknownMemberFunction(type_that_member_is_on.clone()),
4086                    node,
4087                );
4088
4089                None
4090            }
4091        }
4092    }
4093
4094    fn analyze_member_call(
4095        &mut self,
4096        type_that_member_is_on: &TypeRef,
4097        field_name_str: &str,
4098        ast_maybe_generic_arguments: Option<Vec<swamp_ast::GenericParameter>>,
4099        ast_arguments: &[swamp_ast::Expression],
4100        chain_self_is_mutable: bool,
4101        node: &swamp_ast::Node,
4102    ) -> (PostfixKind, TypeRef) {
4103        let generic_arguments = if let Some(ast_generic_arguments) = ast_maybe_generic_arguments {
4104            let mut resolved_types = Vec::new();
4105            for ast_type in ast_generic_arguments {
4106                resolved_types.push(self.analyze_type(ast_type.get_type(), &TypeAnalyzeContext::default()));
4107            }
4108            resolved_types
4109        } else {
4110            vec![]
4111        };
4112
4113        let maybe_function = self
4114            .shared
4115            .state
4116            .associated_impls
4117            .get_member_function(type_that_member_is_on, field_name_str)
4118            .cloned();
4119
4120        let (function_ref, instantiated_signature) = if let Some(found_function) = maybe_function {
4121            let signature = self.analyze_normal_member_call(
4122                type_that_member_is_on,
4123                &found_function,
4124                generic_arguments,
4125                ast_arguments,
4126                chain_self_is_mutable,
4127                node,
4128            );
4129            (found_function, signature)
4130        } else {
4131            let lambda_variables_count = if ast_arguments.is_empty() {
4132                0
4133            } else if let swamp_ast::ExpressionKind::Lambda(variables, ..) = &ast_arguments[0].kind
4134            {
4135                variables.len()
4136            } else {
4137                0
4138            };
4139            let Some((intrinsic_fn, signature)) = self.check_intrinsic_member_signature(
4140                type_that_member_is_on,
4141                field_name_str,
4142                lambda_variables_count,
4143                node,
4144            ) else {
4145                return (PostfixKind::OptionalChainingOperator, self.types().unit());
4146            };
4147            let def = IntrinsicFunctionDefinition {
4148                name: field_name_str.to_string(),
4149                signature,
4150                intrinsic: intrinsic_fn,
4151            };
4152            let function_ref = FunctionRef::from(Function::Intrinsic(
4153                IntrinsicFunctionDefinitionRef::from(def.clone()),
4154            ));
4155            (function_ref, def.signature)
4156        };
4157
4158        let self_type_in_signature = &instantiated_signature.parameters[0];
4159
4160        if self_type_in_signature.is_mutable && !chain_self_is_mutable {
4161            self.add_err(ErrorKind::SelfNotCorrectMutableState, node);
4162        }
4163
4164        let resolved_arguments = self.analyze_and_verify_parameters(
4165            node,
4166            &instantiated_signature.parameters[1..],
4167            ast_arguments,
4168        );
4169
4170        (
4171            PostfixKind::MemberCall(function_ref, resolved_arguments),
4172            TypeRef::from(instantiated_signature.return_type.clone()),
4173        )
4174    }
4175
4176    fn analyze_postfix_member_call(
4177        &mut self,
4178        type_that_member_is_on: &TypeRef,
4179        is_mutable: bool,
4180        member_name: &swamp_ast::Node,
4181        ast_maybe_generic_arguments: Option<Vec<swamp_ast::GenericParameter>>,
4182        ast_arguments: &[swamp_ast::Expression],
4183        suffixes: &mut Vec<Postfix>,
4184    ) -> TypeRef {
4185        let field_name_str = self.get_text(member_name).to_string();
4186
4187        let resolved_node = self.to_node(member_name);
4188
4189        let (kind, return_type) = self.analyze_member_call(
4190            type_that_member_is_on,
4191            &field_name_str,
4192            ast_maybe_generic_arguments,
4193            ast_arguments,
4194            is_mutable,
4195            member_name,
4196        );
4197        let postfix = Postfix {
4198            node: resolved_node,
4199            ty: return_type,
4200            kind,
4201        };
4202
4203        let last_type = postfix.ty.clone();
4204        suffixes.push(postfix);
4205
4206        last_type
4207    }
4208
4209    fn is_compatible_initializer_list_target(
4210        &mut self,
4211        target_type: &TypeRef,
4212        initializer_element_type: &TypeRef,
4213    ) -> bool {
4214        match &*target_type.kind {
4215            TypeKind::VecStorage(vec_element_type, _vec_capacity) => self
4216                .types()
4217                .compatible_with(vec_element_type, initializer_element_type),
4218            TypeKind::FixedCapacityAndLengthArray(array_element_type, _array_capacity) => self
4219                .types()
4220                .compatible_with(array_element_type, initializer_element_type),
4221            _ => false,
4222        }
4223    }
4224
4225    fn is_compatible_initializer_pair_list_target(
4226        &mut self,
4227        target_type: &TypeRef,
4228        initializer_key_type: &TypeRef,
4229        initializer_value_type: &TypeRef,
4230    ) -> bool {
4231        match &*target_type.kind {
4232            TypeKind::MapStorage(storage_key, storage_value, _) => {
4233                self.types()
4234                    .compatible_with(initializer_key_type, storage_key)
4235                    && self
4236                    .types()
4237                    .compatible_with(initializer_value_type, storage_value)
4238            }
4239            _ => false,
4240        }
4241    }
4242
4243    fn types_did_not_match_try_late_coerce_expression(
4244        &mut self,
4245        expr: Expression,
4246        special_expected_type: &TypeRef,
4247        special_encountered_type: &TypeRef,
4248        node: &swamp_ast::Node,
4249    ) -> Expression {
4250        let expected_type = special_expected_type;
4251        let encountered_type = special_encountered_type;
4252        let encountered_is_optional = matches!(&*encountered_type.kind, TypeKind::Optional(_));
4253        if let TypeKind::Optional(expected_inner_type) = &*expected_type.kind {
4254            let inner_is_also_optional =
4255                matches!(&*expected_inner_type.kind, TypeKind::Optional(_));
4256            // If an optional is expected, we can wrap it if this type has the exact same
4257            // inner type
4258            assert!(!inner_is_also_optional);
4259
4260            // First make sure it is not already an optional type. we can not wrap an option with an option
4261            // TODO: Improve error handling
4262            if !encountered_is_optional {
4263                // good it isn't, lets see if they share inner types
4264                if self
4265                    .types()
4266                    .compatible_with(expected_inner_type, encountered_type)
4267                {
4268                    // they share inner types as well, lets wrap it up
4269                    let wrapped = self.create_expr(
4270                        ExpressionKind::Option(Option::from(Box::new(expr))),
4271                        expected_type.clone(),
4272                        node,
4273                    );
4274                    return wrapped;
4275                }
4276            }
4277        }
4278
4279        if matches!(&*expected_type.kind, &TypeKind::Bool) {
4280            // if it has a mut or immutable optional, then it works well to wrap it
4281            if encountered_is_optional {
4282                let bool_type = self.types().bool();
4283                let wrapped = self.create_expr(
4284                    ExpressionKind::CoerceOptionToBool(Box::from(expr)),
4285                    bool_type,
4286                    node,
4287                );
4288                return wrapped;
4289            }
4290        }
4291
4292        if matches!(
4293            (&*expected_type.kind, &*encountered_type.kind),
4294            (TypeKind::Codepoint, TypeKind::Int)
4295        ) {
4296            let coerced = self.create_expr(
4297                ExpressionKind::CoerceIntToChar(Box::new(expr)),
4298                expected_type.clone(),
4299                node,
4300            );
4301            return coerced;
4302        }
4303
4304        error!(?expected_type, ?encountered_type, "incompatible");
4305        self.create_err(
4306            ErrorKind::IncompatibleTypes {
4307                expected: expected_type.clone(),
4308                found: encountered_type.clone(),
4309            },
4310            node,
4311        )
4312    }
4313
4314    #[must_use]
4315    pub fn analyze_generic_parameter_usize(&self, generic_parameter: &GenericParameter) -> usize {
4316        let usize_node = generic_parameter.get_unsigned_int_node();
4317        let usize_str = self.get_text(usize_node);
4318        Self::str_to_unsigned_int(usize_str).unwrap() as usize
4319    }
4320
4321    #[must_use]
4322    pub fn analyze_generic_parameter_usize_tuple(
4323        &self,
4324        generic_parameter: &GenericParameter,
4325    ) -> (usize, usize) {
4326        let (first, second) = generic_parameter.get_unsigned_int_tuple_nodes();
4327        let first_str = self.get_text(first);
4328        let second_str = self.get_text(second);
4329        let first_value = Self::str_to_unsigned_int(first_str).unwrap() as usize;
4330        let second_value = Self::str_to_unsigned_int(second_str).unwrap() as usize;
4331
4332        (first_value, second_value)
4333    }
4334
4335    pub fn analyze_special_named_type(
4336        &mut self,
4337        path: &[String],
4338        name: &str,
4339        ast_generic_parameters: &[GenericParameter],
4340    ) -> Option<TypeRef> {
4341        let converted_type = match name {
4342            "Any" => {
4343                let new_type = self.shared.state.types.any();
4344                let default_node = swamp_ast::Node::default();
4345                new_type
4346            }
4347            "String" => {
4348                if ast_generic_parameters.len() == 1 {
4349                    let fixed_size =
4350                        self.analyze_generic_parameter_usize(&ast_generic_parameters[0]);
4351                    let new_type = self.shared.state.types.string_storage(fixed_size);
4352                    let default_node = swamp_ast::Node::default();
4353                    self.add_default_functions(&new_type, &default_node);
4354                    new_type
4355                } else {
4356                    return None;
4357                }
4358            }
4359            "Vec" => {
4360                if ast_generic_parameters.len() == 1 {
4361                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type(), &TypeAnalyzeContext::default());
4362                    let vec_type = self.shared.state.types.dynamic_vec_view(&element_type);
4363                    // Generate default functions for the new dynamic vec view type
4364                    let default_node = swamp_ast::Node::default();
4365                    self.add_default_functions(&vec_type, &default_node);
4366                    vec_type
4367                } else if ast_generic_parameters.len() == 2 {
4368                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type(), &TypeAnalyzeContext::default());
4369                    let fixed_size =
4370                        self.analyze_generic_parameter_usize(&ast_generic_parameters[1]);
4371                    let vec_storage_type = self
4372                        .shared
4373                        .state
4374                        .types
4375                        .vec_storage(&element_type, fixed_size);
4376                    // Generate default functions for the new vec storage type
4377                    let default_node = swamp_ast::Node::default();
4378                    self.add_default_functions(&vec_storage_type, &default_node);
4379                    vec_storage_type
4380                } else {
4381                    panic!("todo: make this into an error")
4382                }
4383            }
4384            "Stack" => {
4385                if ast_generic_parameters.len() == 1 {
4386                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type(), &TypeAnalyzeContext::default());
4387                    let stack_view_type = self.shared.state.types.stack_view(&element_type);
4388                    // Generate default functions for the new stack view type
4389                    let default_node = swamp_ast::Node::default();
4390                    self.add_default_functions(&stack_view_type, &default_node);
4391                    stack_view_type
4392                } else if ast_generic_parameters.len() == 2 {
4393                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type(), &TypeAnalyzeContext::default());
4394                    let fixed_size =
4395                        self.analyze_generic_parameter_usize(&ast_generic_parameters[1]);
4396                    let stack_storage_type = self
4397                        .shared
4398                        .state
4399                        .types
4400                        .stack_storage(&element_type, fixed_size);
4401                    // Generate default functions for the new stack storage type
4402                    let default_node = swamp_ast::Node::default();
4403                    self.add_default_functions(&stack_storage_type, &default_node);
4404                    stack_storage_type
4405                } else {
4406                    panic!("todo: make this into an error")
4407                }
4408            }
4409            "Queue" => {
4410                if ast_generic_parameters.len() == 1 {
4411                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type(), &TypeAnalyzeContext::default());
4412                    let queue_view_type = self.shared.state.types.queue_view(&element_type);
4413                    // Generate default functions for the new queue view type
4414                    let default_node = swamp_ast::Node::default();
4415                    self.add_default_functions(&queue_view_type, &default_node);
4416                    queue_view_type
4417                } else if ast_generic_parameters.len() == 2 {
4418                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type(), &TypeAnalyzeContext::default());
4419                    let fixed_size =
4420                        self.analyze_generic_parameter_usize(&ast_generic_parameters[1]);
4421                    let queue_storage_type = self
4422                        .shared
4423                        .state
4424                        .types
4425                        .queue_storage(&element_type, fixed_size);
4426                    // Generate default functions for the new queue storage type
4427                    let default_node = swamp_ast::Node::default();
4428                    self.add_default_functions(&queue_storage_type, &default_node);
4429                    queue_storage_type
4430                } else {
4431                    panic!("todo: make this into an error")
4432                }
4433            }
4434            "Sparse" => {
4435                if ast_generic_parameters.len() == 1 {
4436                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type(), &TypeAnalyzeContext::default());
4437                    let sparse_view_type = self.shared.state.types.sparse_view(&element_type);
4438                    // Generate default functions for the new sparse view type
4439                    let default_node = swamp_ast::Node::default();
4440                    self.add_default_functions(&sparse_view_type, &default_node);
4441                    sparse_view_type
4442                } else if ast_generic_parameters.len() == 2 {
4443                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type(), &TypeAnalyzeContext::default());
4444                    let fixed_size =
4445                        self.analyze_generic_parameter_usize(&ast_generic_parameters[1]);
4446                    let sparse_storage_type = self
4447                        .shared
4448                        .state
4449                        .types
4450                        .sparse_storage(&element_type, fixed_size);
4451                    // Generate default functions for the new sparse storage type
4452                    let default_node = swamp_ast::Node::default();
4453                    self.add_default_functions(&sparse_storage_type, &default_node);
4454                    sparse_storage_type
4455                } else {
4456                    panic!("todo: make this into an error")
4457                }
4458            }
4459
4460            "Grid" => {
4461                if ast_generic_parameters.len() == 1 {
4462                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type(), &TypeAnalyzeContext::default());
4463                    let grid_view_type = self.shared.state.types.grid_view(&element_type);
4464                    // Generate default functions for the new grid view type
4465                    let default_node = swamp_ast::Node::default();
4466                    self.add_default_functions(&grid_view_type, &default_node);
4467                    grid_view_type
4468                } else if ast_generic_parameters.len() == 2 {
4469                    let element_type = self.analyze_type(ast_generic_parameters[0].get_type(), &TypeAnalyzeContext::default());
4470                    let (width, height) =
4471                        self.analyze_generic_parameter_usize_tuple(&ast_generic_parameters[1]);
4472                    let grid_storage_type =
4473                        self.shared
4474                            .state
4475                            .types
4476                            .grid_storage(&element_type, width, height);
4477                    // Generate default functions for the new grid storage type
4478                    let default_node = swamp_ast::Node::default();
4479                    self.add_default_functions(&grid_storage_type, &default_node);
4480                    grid_storage_type
4481                } else {
4482                    panic!("todo: make this into an error")
4483                }
4484            }
4485
4486            _ => return None,
4487        };
4488
4489        Some(converted_type)
4490    }
4491
4492    fn special_static_member(
4493        &self,
4494        type_identifier: &QualifiedTypeIdentifier,
4495        member_name_node: &swamp_ast::Node,
4496    ) -> Option<Function> {
4497        if type_identifier.generic_params.is_empty() {
4498            return None;
4499        }
4500
4501        if type_identifier.module_path.is_some() {
4502            return None;
4503        }
4504
4505        let member_name = self.get_text(member_name_node);
4506        let name = self.get_text(&type_identifier.name.0);
4507
4508        match name {
4509            "Stack" => None,
4510            _ => None,
4511        }
4512    }
4513
4514    fn analyze_subscript_int(&mut self, collection_type: TypeRef, unsigned_int_expression: Expression) -> (Postfix, TypeRef) {
4515        let node = &unsigned_int_expression.node;
4516        match &*collection_type.kind {
4517            TypeKind::QueueStorage(element_type, _)
4518            | TypeKind::StackStorage(element_type, _)
4519            | TypeKind::StackView(element_type)
4520            | TypeKind::VecStorage(element_type, _)
4521            | TypeKind::StringStorage(element_type, _, _)
4522            | TypeKind::String(element_type, _)
4523            | TypeKind::FixedCapacityAndLengthArray(element_type, _)
4524            | TypeKind::DynamicLengthVecView(element_type)
4525            | TypeKind::SliceView(element_type) => {
4526                let vec_type = VecType {
4527                    element: element_type.clone(),
4528                };
4529
4530                let postfix = Postfix {
4531                    node: node.clone(),
4532                    ty: collection_type.clone(),
4533                    kind: PostfixKind::VecSubscript(
4534                        vec_type,
4535                        unsigned_int_expression,
4536                    ),
4537                };
4538
4539                (postfix, element_type.clone())
4540            }
4541            // Sparse
4542            TypeKind::SparseStorage(element_type, _)
4543            | TypeKind::SparseView(element_type) => {
4544                let sparse_type = SparseType {
4545                    element: element_type.clone(),
4546                };
4547
4548
4549                let postfix = Postfix {
4550                    node: node.clone(),
4551                    ty: collection_type.clone(),
4552                    kind: PostfixKind::SparseSubscript(
4553                        sparse_type,
4554                        unsigned_int_expression,
4555                    ),
4556                };
4557
4558                (postfix, element_type.clone())
4559            }
4560
4561            _ => {
4562                self
4563                    .add_err_resolved(ErrorKind::CanNotSubscriptWithThatType, node);
4564
4565                let error_vec_type = VecType {
4566                    element: self.types().unit(),
4567                };
4568
4569                let error_postfix = Postfix {
4570                    node: node.clone(),
4571                    ty: collection_type.clone(),
4572                    kind: PostfixKind::VecSubscript(
4573                        error_vec_type,
4574                        unsigned_int_expression,
4575                    ),
4576                };
4577
4578                (error_postfix, self.types().unit())
4579            }
4580        }
4581    }
4582
4583
4584    fn analyze_subscript_range(&mut self, collection_type: TypeRef, range_expression: Expression) -> (Postfix, TypeRef) {
4585        let node = &range_expression.node;
4586        match &*collection_type.kind {
4587            TypeKind::QueueStorage(element_type, _)
4588            | TypeKind::StackStorage(element_type, _)
4589            | TypeKind::StackView(element_type)
4590            | TypeKind::VecStorage(element_type, _)
4591            | TypeKind::StringStorage(element_type, _, _)
4592            | TypeKind::String(element_type, _)
4593            | TypeKind::FixedCapacityAndLengthArray(element_type, _)
4594            | TypeKind::DynamicLengthVecView(element_type)
4595            | TypeKind::SliceView(element_type) => {
4596                let vec_type = VecType {
4597                    element: element_type.clone(),
4598                };
4599
4600                let postfix = Postfix {
4601                    node: node.clone(),
4602                    ty: collection_type.clone(),
4603                    kind: PostfixKind::VecSubscriptRange(
4604                        vec_type,
4605                        range_expression,
4606                    ),
4607                };
4608
4609                // A range subscript returns the same type again
4610                (postfix, collection_type.clone())
4611            }
4612
4613            _ => {
4614                self
4615                    .add_err_resolved(ErrorKind::CanNotSubscriptWithThatType, node);
4616
4617                let error_vec_type = VecType {
4618                    element: self.types().unit(),
4619                };
4620
4621                let error_postfix = Postfix {
4622                    node: node.clone(),
4623                    ty: collection_type.clone(),
4624                    kind: PostfixKind::VecSubscriptRange(
4625                        error_vec_type,
4626                        range_expression,
4627                    ),
4628                };
4629
4630                (error_postfix, self.types().unit())
4631            }
4632        }
4633    }
4634    fn analyze_map_subscript(&mut self, key_type: &TypeRef, value_type: &TypeRef, lookup_expr: &swamp_ast::Expression) -> (Postfix, TypeRef) {
4635        let key_context = TypeContext::new_argument(key_type, false);
4636        let key_expression = self.analyze_expression(lookup_expr, &key_context);
4637
4638        let map_type = MapType {
4639            key: key_type.clone(),
4640            value: value_type.clone(),
4641        };
4642
4643        let postfix = Postfix {
4644            node: self.to_node(&lookup_expr.node),
4645            ty: key_type.clone(),
4646            kind: PostfixKind::MapSubscript(map_type, key_expression),
4647        };
4648
4649        (postfix, value_type.clone())
4650    }
4651}