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::ArgumentExpression;
9use swamp_semantic::err::ErrorKind;
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            let resolved_expr = self.analyze_expression(argument_expr, &context);
65            ArgumentExpression::Expression(resolved_expr)
66        }
67    }
68
69    /// # Errors
70    ///
71    pub fn analyze_and_verify_parameters(
72        &mut self,
73        node: &swamp_ast::Node,
74        fn_parameters: &[TypeForParameter],
75        arguments: &[swamp_ast::Expression],
76    ) -> Vec<ArgumentExpression> {
77        if fn_parameters.len() != arguments.len() {
78            self.add_err(
79                ErrorKind::WrongNumberOfArguments(fn_parameters.len(), arguments.len()),
80                node,
81            );
82            return vec![];
83        }
84
85        let mut resolved_arguments = Vec::new();
86        for (fn_parameter, argument_expr) in fn_parameters.iter().zip(arguments) {
87            let mut_or_immutable = self.analyze_argument(fn_parameter, argument_expr);
88            resolved_arguments.push(mut_or_immutable);
89        }
90
91        resolved_arguments
92    }
93
94    /// # Errors
95    ///
96    pub fn analyze_mut_or_immutable_expression(
97        &mut self,
98        expr: &swamp_ast::Expression,
99        context: &TypeContext,
100        location_side: LocationSide,
101    ) -> ArgumentExpression {
102        let maybe_borrow_or_normal_expression = self.analyze_maybe_ref_expression(expr);
103
104        if maybe_borrow_or_normal_expression
105            .has_borrow_mutable_reference
106            .is_some()
107        {
108            ArgumentExpression::BorrowMutableReference(self.analyze_to_location(
109                &maybe_borrow_or_normal_expression.ast_expression,
110                context,
111                location_side,
112            ))
113        } else {
114            ArgumentExpression::Expression(
115                self.analyze_expression(&maybe_borrow_or_normal_expression.ast_expression, context),
116            )
117        }
118    }
119}