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