swamp_analyzer/
call.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 */
5use crate::TypeContext;
6use crate::{Analyzer, LocationSide};
7use source_map_node::Node;
8use swamp_semantic::err::ErrorKind;
9use swamp_semantic::{ArgumentExpression, Expression, ExpressionKind};
10use swamp_types::prelude::*;
11
12pub struct MaybeBorrowMutRefExpression {
13    pub ast_expression: swamp_ast::Expression,
14    pub has_borrow_mutable_reference: Option<Node>,
15}
16
17impl Analyzer<'_> {
18    /*
19    TODO: @ideas
20    The analyzer should be more explicit in how the values are transferred, to make it easier and more consistent for the code generator.
21
22    - PassSimpleValue (For simple (primitive) type parameters, not mut, e.g. `a: Int`)
23    - PassSimpleValueWithCopyback (For **mut** simple (primitive) parameters, e.g. `mut a: Int`)
24    - PassComplexAddressFromLValue (For complex type parameters, argument is LValue. can be used for both `mut` and not mut, but is mandatory if is mut)
25    - PassComplexAddressFromRValueMaterialization (For complex type parameters, argument is RValue. Param must NOT be mut)
26
27    */
28    /// # Errors
29    ///
30    pub fn analyze_argument(
31        &mut self,
32        fn_parameter: &TypeForParameter,
33        argument_expr: &swamp_ast::Expression,
34    ) -> ArgumentExpression {
35        let context = TypeContext::new_argument(
36            &fn_parameter.resolved_type,
37            false, // Function arguments cannot provide storage for aggregate return values
38        );
39
40        let ref_checked_argument = self.analyze_maybe_ref_expression(argument_expr);
41
42        if fn_parameter.is_mutable {
43            if ref_checked_argument.has_borrow_mutable_reference.is_none() {
44                // if the parameter is mutable you must pass in mutable reference to it
45                let expr = self.create_err(ErrorKind::ArgumentIsNotMutable, &argument_expr.node);
46                return ArgumentExpression::Expression(expr);
47            }
48            let mut_location = self.analyze_to_location(
49                &ref_checked_argument.ast_expression,
50                &context,
51                LocationSide::Rhs,
52            );
53
54            ArgumentExpression::BorrowMutableReference(mut_location)
55        } else {
56            if ref_checked_argument.has_borrow_mutable_reference.is_some() {
57                {
58                    let expr =
59                        self.create_err(ErrorKind::ParameterIsNotMutable, &argument_expr.node);
60                    // Why did you pass in a mutable reference to something that can not do anything useful with it
61                    return ArgumentExpression::Expression(expr);
62                }
63            }
64
65            let resolved_expr = self.analyze_expression(
66                &ref_checked_argument.ast_expression,
67                &context.with_ephemeral(),
68            );
69            // Check if this expression needs materialization for fixed-size types
70            if self.needs_materialization(&resolved_expr) {
71                // and then check if it will be possible to create temporary storage:
72                if resolved_expr.ty.can_be_materialized() {
73                    ArgumentExpression::MaterializedExpression(resolved_expr)
74                } else {
75                    // Error
76                    ArgumentExpression::Expression(
77                        self.create_err(
78                            ErrorKind::CanNotCreateTemporaryStorage,
79                            &argument_expr.node,
80                        ),
81                    )
82                }
83            } else {
84                ArgumentExpression::Expression(resolved_expr)
85            }
86        }
87    }
88
89    /// # Errors
90    ///
91    pub fn analyze_and_verify_parameters(
92        &mut self,
93        node: &swamp_ast::Node,
94        fn_parameters: &[TypeForParameter],
95        arguments: &[swamp_ast::Expression],
96    ) -> Vec<ArgumentExpression> {
97        if fn_parameters.len() != arguments.len() {
98            self.add_err(
99                ErrorKind::WrongNumberOfArguments(fn_parameters.len(), arguments.len()),
100                node,
101            );
102            return vec![];
103        }
104
105        if fn_parameters.len() > Self::MAX_PARAMETER_COUNT {
106            self.add_err(
107                ErrorKind::TooManyParameters {
108                    encountered: fn_parameters.len(),
109                    allowed: Self::MAX_PARAMETER_COUNT,
110                },
111                node,
112            );
113            return vec![];
114        }
115
116        let mut resolved_arguments = Vec::new();
117        for (fn_parameter, argument_expr) in fn_parameters.iter().zip(arguments) {
118            let mut_or_immutable = self.analyze_argument(fn_parameter, argument_expr);
119            resolved_arguments.push(mut_or_immutable);
120        }
121
122        resolved_arguments
123    }
124
125    /// # Errors
126    ///
127    pub fn analyze_mut_or_immutable_expression(
128        &mut self,
129        expr: &swamp_ast::Expression,
130        context: &TypeContext,
131        location_side: LocationSide,
132    ) -> ArgumentExpression {
133        let maybe_borrow_or_normal_expression = self.analyze_maybe_ref_expression(expr);
134
135        if maybe_borrow_or_normal_expression
136            .has_borrow_mutable_reference
137            .is_some()
138        {
139            ArgumentExpression::BorrowMutableReference(self.analyze_to_location(
140                &maybe_borrow_or_normal_expression.ast_expression,
141                context,
142                location_side,
143            ))
144        } else {
145            ArgumentExpression::Expression(
146                self.analyze_expression(&maybe_borrow_or_normal_expression.ast_expression, context),
147            )
148        }
149    }
150
151    /// Determines if an expression needs materialization (temporary storage)
152    /// This applies to expressions that produce values but don't have a direct memory location
153    /// Only applies to non-mutable parameters with blittable (fixed-size) types
154    /*
155        pub(crate) fn rvalue_needs_memory_location_to_materialize_in(
156        layout_cache: &mut LayoutCache,
157        expr: &Expression,
158    ) -> bool {
159        let specific_kind_of_expression_needs_memory_target = match &expr.kind {
160            // TODO: Should have more robust check here. maybe check primitives instead and invert?
161            ExpressionKind::EnumVariantLiteral(_, _)
162            | ExpressionKind::TupleLiteral(_)
163            | ExpressionKind::InitializerList(_, _)
164            | ExpressionKind::InitializerPairList(_, _) => true,
165            ExpressionKind::Option(_)
166            | ExpressionKind::AnonymousStructLiteral(_)
167            | ExpressionKind::CoerceToAny(_) => true,
168            _ => false,
169        };
170
171        if specific_kind_of_expression_needs_memory_target {
172            true
173        } else {
174            // Easy to forget that you should also check if it's a function call with a return type requiring memory allocation
175            match &expr.kind {
176                ExpressionKind::InternalCall(_, _)
177                | ExpressionKind::HostCall(_, _)
178                | ExpressionKind::IntrinsicCallEx(_, _) => {
179                    let basic_type = layout_cache.layout(&expr.ty);
180                    basic_type.is_aggregate()
181                }
182                _ => false,
183            }
184        }
185    }
186     */
187    const fn needs_materialization(&self, expr: &Expression) -> bool {
188        match &expr.kind {
189            ExpressionKind::ConstantAccess(_) => false,
190            ExpressionKind::VariableAccess(_) => false,
191            ExpressionKind::BinaryOp(_) => true,
192            ExpressionKind::UnaryOp(_) => true,
193            ExpressionKind::PostfixChain(_, _) => true,
194            ExpressionKind::CoerceOptionToBool(_) => false,
195            ExpressionKind::CoerceIntToChar(_) => false,
196            ExpressionKind::CoerceIntToByte(_) => false,
197            ExpressionKind::CoerceToAny(_) => true,
198            ExpressionKind::IntrinsicCallEx(_, _) => true,
199            ExpressionKind::InternalCall(_, _) => true,
200            ExpressionKind::HostCall(_, _) => true,
201            ExpressionKind::VariableDefinition(_, _) => true,
202            ExpressionKind::VariableDefinitionLValue(_, _) => true,
203            ExpressionKind::VariableReassignment(_, _) => true,
204            ExpressionKind::Assignment(_, _) => true,
205            ExpressionKind::CompoundAssignment(_, _, _) => true,
206            ExpressionKind::AnonymousStructLiteral(_) => true,
207            ExpressionKind::NamedStructLiteral(_) => true,
208            ExpressionKind::FloatLiteral(_) => true,
209            ExpressionKind::NoneLiteral => true,
210            ExpressionKind::IntLiteral(_) => true,
211            ExpressionKind::ByteLiteral(_) => true,
212            ExpressionKind::StringLiteral(_) => true,
213            ExpressionKind::BoolLiteral(_) => true,
214            ExpressionKind::EnumVariantLiteral(_, _) => true,
215            ExpressionKind::TupleLiteral(_) => true,
216            ExpressionKind::InitializerList(_, _) => true,
217            ExpressionKind::InitializerPairList(_, _) => true,
218            ExpressionKind::Option(_) => true,
219            ExpressionKind::ForLoop(_, _, _) => true,
220            ExpressionKind::WhileLoop(_, _) => true,
221            ExpressionKind::Block(_) => true,
222            ExpressionKind::Match(_) => true,
223            ExpressionKind::Guard(_) => true,
224            ExpressionKind::If(_, _, _) => true,
225            ExpressionKind::When(_, _, _) => true,
226            ExpressionKind::TupleDestructuring(_, _, _) => true,
227            ExpressionKind::Lambda(_, _) => false,
228            ExpressionKind::BorrowMutRef(_) => true,
229            ExpressionKind::Error(_) => true,
230        }
231    }
232}