swamp_script_semantic/
instantiator.rs

1use crate::prelude::InstantiationCache;
2use crate::{
3    AssociatedImpls, ExternalFunctionDefinition, Function, FunctionScopeState,
4    InternalFunctionDefinition, LocalIdentifier, SemanticError,
5};
6use seq_map::SeqMap;
7use std::rc::Rc;
8use swamp_script_node::Node;
9use swamp_script_types::{
10    AnonymousStructType, NamedStructType, ParameterizedTypeBlueprint,
11    ParameterizedTypeBlueprintInfo, ParameterizedTypeKind, Signature, StructTypeField, Type,
12    TypeForParameter, all_types_are_concrete, all_types_are_concrete_or_unit,
13};
14
15#[derive(Debug)]
16pub struct TypeVariableScope {
17    pub type_variables: SeqMap<String, Type>,
18}
19
20impl TypeVariableScope {
21    #[must_use]
22    pub const fn new(scope: SeqMap<String, Type>) -> Self {
23        Self {
24            type_variables: scope,
25        }
26    }
27
28    pub(crate) fn variables(&self) -> Vec<Type> {
29        self.type_variables.values().cloned().collect()
30    }
31}
32#[derive(Clone, Debug)]
33pub struct Instantiator {
34    pub associated_impls: AssociatedImpls,
35    pub instantiation_cache: InstantiationCache,
36}
37
38impl Instantiator {
39    pub fn new() -> Self {
40        Self {
41            associated_impls: AssociatedImpls::new(),
42            instantiation_cache: InstantiationCache::new(),
43        }
44    }
45    pub fn instantiate_blueprint_and_members(
46        &mut self,
47        blueprint: &ParameterizedTypeBlueprint,
48        analyzed_type_parameters: &[Type],
49    ) -> Result<Type, SemanticError> {
50        assert!(all_types_are_concrete_or_unit(analyzed_type_parameters));
51
52        if let Some(existing) = self.instantiation_cache.get(
53            &blueprint.defined_in_module_path,
54            &blueprint.name(),
55            analyzed_type_parameters,
56        ) {
57            return Ok(existing.clone());
58        }
59
60        let scope = Self::create_type_parameter_scope_from_variables(
61            &blueprint.type_variables,
62            analyzed_type_parameters,
63        )?;
64        let (_ignore_if_changed, instantiated_type) =
65            self.instantiate_base_type_from_blueprint(blueprint, &scope)?;
66
67        let new_impls = {
68            let mut new_impls = SeqMap::new();
69            let maybe_member_functions = self
70                .associated_impls
71                .functions
72                .get(&Type::Blueprint(blueprint.clone()))
73                .cloned();
74            if let Some(found_member_functions) = maybe_member_functions {
75                for (func_name, func_ref) in &found_member_functions.functions {
76                    let (_replaced, new_signature) = self.instantiate_signature(
77                        &instantiated_type,
78                        func_ref.signature(),
79                        &scope,
80                    )?;
81                    let new_func = match &**func_ref {
82                        Function::Internal(internal) => {
83                            let func_ref = Rc::new(InternalFunctionDefinition {
84                                body: internal.body.clone(),
85                                name: LocalIdentifier(Node::default()),
86                                assigned_name: format!("instantiated {func_name}"),
87                                signature: new_signature.clone(),
88                                variable_scopes: FunctionScopeState::new(
89                                    *new_signature.return_type.clone(),
90                                ), // self.scope.clone(),
91                                function_scope_state: Vec::new(), // self.function_variables.clone(),
92                                program_unique_id: internal.program_unique_id,
93                            });
94                            Function::Internal(func_ref)
95                        }
96                        Function::External(blueprint_external) => {
97                            let func_ref = Rc::new(ExternalFunctionDefinition {
98                                name: None,
99                                assigned_name: String::new(),
100                                signature: new_signature,
101                                id: blueprint_external.id,
102                            });
103                            Function::External(func_ref)
104                        }
105                    };
106                    new_impls.insert(func_name.clone(), new_func).unwrap();
107                }
108            }
109            new_impls
110        };
111
112        self.associated_impls.prepare(&instantiated_type);
113        for (name, func) in &new_impls {
114            self.associated_impls.add_member_function(
115                &instantiated_type,
116                name,
117                func.clone().into(),
118            )?;
119        }
120
121        self.instantiation_cache
122            .add(
123                &blueprint.defined_in_module_path,
124                &blueprint.name(),
125                instantiated_type.clone(),
126                analyzed_type_parameters,
127            )
128            .unwrap();
129
130        Ok(instantiated_type)
131    }
132
133    fn create_type_parameter_scope(
134        parameters: &[Type],
135        concrete: &[Type],
136    ) -> Result<TypeVariableScope, SemanticError> {
137        assert_eq!(parameters.len(), concrete.len(), "wrong parameter count");
138
139        let mut scope = SeqMap::new();
140        for (param, concrete) in parameters.iter().zip(concrete) {
141            if let Type::Variable(type_variable_name) = param {
142                scope
143                    .insert(type_variable_name.clone(), concrete.clone())
144                    .unwrap();
145            };
146        }
147
148        Ok(TypeVariableScope::new(scope))
149    }
150
151    fn create_type_parameter_scope_from_variables(
152        variables: &[String],
153        concrete_types: &[Type],
154    ) -> Result<TypeVariableScope, SemanticError> {
155        assert_eq!(
156            variables.len(),
157            concrete_types.len(),
158            "wrong parameter count"
159        );
160
161        assert!(all_types_are_concrete_or_unit(concrete_types));
162
163        let mut scope = SeqMap::new();
164        for (param, concrete) in variables.iter().zip(concrete_types) {
165            scope.insert(param.clone(), concrete.clone()).unwrap();
166        }
167
168        Ok(TypeVariableScope::new(scope))
169    }
170
171    fn instantiate_base_type_from_blueprint(
172        &mut self,
173        blueprint: &ParameterizedTypeBlueprint,
174        scope: &TypeVariableScope,
175    ) -> Result<(bool, Type), SemanticError> {
176        match &blueprint.kind {
177            ParameterizedTypeKind::Struct(struct_ref) => self.instantiate_struct(
178                Some(&Type::Blueprint(blueprint.clone())),
179                struct_ref,
180                scope,
181            ),
182            ParameterizedTypeKind::Enum(_) => todo!(),
183        }
184    }
185
186    fn instantiate_type_in_signature(
187        &mut self,
188        current_self: &Type,
189        ty: &Type,
190        type_variables: &TypeVariableScope,
191    ) -> Result<(bool, Type), SemanticError> {
192        match ty {
193            Type::Blueprint(_) => {
194                // TODO: Check if this hack is still needed
195                Ok((false, current_self.clone()))
196            }
197            _ => self.instantiate_type_if_needed(Some(current_self), ty, type_variables),
198        }
199    }
200
201    pub fn instantiate_signature(
202        &mut self,
203        self_type: &Type,
204        signature: &Signature,
205        scope: &TypeVariableScope,
206    ) -> Result<(bool, Signature), SemanticError> {
207        let mut was_replaced = false;
208        let mut instantiated_type_for_parameters = Vec::new();
209        for type_for_parameter in &signature.parameters {
210            let (type_was_replaced, resolved) = self.instantiate_type_in_signature(
211                self_type,
212                &type_for_parameter.resolved_type,
213                scope,
214            )?;
215
216            if type_was_replaced {
217                was_replaced = true;
218            }
219            instantiated_type_for_parameters.push(TypeForParameter {
220                name: type_for_parameter.name.clone(),
221                resolved_type: resolved,
222                is_mutable: type_for_parameter.is_mutable,
223                node: type_for_parameter.node.clone(),
224            });
225        }
226
227        let (return_type_was_replaced, instantiated_return_type) =
228            self.instantiate_type_in_signature(self_type, &signature.return_type, scope)?;
229        if return_type_was_replaced {
230            was_replaced = true;
231        }
232
233        let new_signature = Signature {
234            parameters: instantiated_type_for_parameters,
235            return_type: Box::new(instantiated_return_type),
236        };
237
238        Ok((was_replaced, new_signature))
239    }
240
241    fn instantiate_types_if_needed(
242        &mut self,
243        current_self: Option<&Type>,
244
245        types: &[Type],
246        type_variables: &TypeVariableScope,
247    ) -> Result<(bool, Vec<Type>), SemanticError> {
248        let mut converted = Vec::new();
249
250        for ty in types {
251            let (_was_converted, instantiated_type) =
252                self.instantiate_type_if_needed(current_self, ty, type_variables)?;
253
254            converted.push(instantiated_type);
255        }
256
257        Ok((true, converted))
258    }
259
260    // TODO: This function seems a bit broad, are all three cases needed?
261    fn extract_blueprint_info(ty: &Type) -> Option<ParameterizedTypeBlueprintInfo> {
262        match ty {
263            Type::Blueprint(bp) => Some(bp.info()),
264            Type::NamedStruct(named) => Some(named.blueprint_info.clone().unwrap()),
265            Type::Generic(bp, _) => Some(bp.info()),
266            _ => None,
267        }
268    }
269
270    fn instantiate_type_if_needed(
271        &mut self,
272        current_self: Option<&Type>,
273        ty: &Type,
274        type_variables: &TypeVariableScope,
275    ) -> Result<(bool, Type), SemanticError> {
276        if let Some(cs) = current_self {
277            if let Some(cs_bp) = Self::extract_blueprint_info(cs) {
278                let other = Self::extract_blueprint_info(&ty);
279                if let Some(found_other) = other {
280                    if found_other == cs_bp {
281                        return Ok((false, cs.clone()));
282                    }
283                }
284            }
285        }
286
287        let (replaced, result_type) = match ty {
288            Type::Generic(parameterized_type, arguments) => {
289                let (_was_replaced, new_arguments) =
290                    self.instantiate_types_if_needed(current_self, arguments, type_variables)?;
291                if all_types_are_concrete(&new_arguments) {
292                    let new_type =
293                        self.instantiate_blueprint_and_members(parameterized_type, &new_arguments)?;
294                    (true, new_type)
295                } else {
296                    panic!("Cannot instantiate generics with unresolved parameters")
297                }
298            }
299
300            Type::Variable(type_variable) => {
301                let found_type = type_variables
302                    .type_variables
303                    .get(type_variable)
304                    .ok_or(SemanticError::UnknownTypeVariable)?;
305                assert!(found_type.is_concrete());
306                (true, found_type.clone())
307            }
308
309            Type::Blueprint(_blueprint) => {
310                //error!(?blueprint, "not allowed with blueprints here for types");
311                panic!("not allowed with blueprints here for types")
312            }
313
314            Type::Tuple(types) => {
315                let (was_replaced, new_types) =
316                    self.instantiate_types_if_needed(current_self, types, type_variables)?;
317                (was_replaced, Type::Tuple(new_types))
318            }
319
320            Type::Optional(inner_type) => {
321                let (was_replaced, new_type) =
322                    self.instantiate_type_if_needed(current_self, inner_type, type_variables)?;
323                (was_replaced, Type::Optional(Box::new(new_type)))
324            }
325
326            Type::Slice(inner_type) => {
327                let (was_replaced, new_type) =
328                    self.instantiate_type_if_needed(current_self, inner_type, type_variables)?;
329                (was_replaced, Type::Slice(Box::new(new_type)))
330            }
331
332            Type::SlicePair(key_type, value_type) => {
333                let (key_type_was_replaced, new_key_type) =
334                    self.instantiate_type_if_needed(current_self, key_type, type_variables)?;
335                let (value_type_was_replaced, new_value_type) =
336                    self.instantiate_type_if_needed(current_self, value_type, type_variables)?;
337                (
338                    key_type_was_replaced || value_type_was_replaced,
339                    Type::SlicePair(Box::new(new_key_type), Box::new(new_value_type)),
340                )
341            }
342
343            _ => (false, ty.clone()),
344        };
345
346        Ok((replaced, result_type))
347    }
348
349    fn parameterized_name(name: &str, parameters: &[Type]) -> String {
350        let type_strings: Vec<String> = parameters
351            .iter()
352            .map(std::string::ToString::to_string)
353            .collect();
354
355        format!("{}<{}>", name, type_strings.join(","))
356    }
357
358    fn instantiate_struct(
359        &mut self,
360        current_self: Option<&Type>,
361        struct_type: &NamedStructType,
362        type_variables: &TypeVariableScope,
363    ) -> Result<(bool, Type), SemanticError> {
364        let mut was_any_replaced = false;
365        let mut new_fields = SeqMap::new();
366        for (name, field) in &struct_type.anon_struct_type.field_name_sorted_fields {
367            let (was_replaced, new_type) =
368                self.instantiate_type_if_needed(current_self, &field.field_type, type_variables)?;
369            was_any_replaced |= was_replaced;
370            let new_field = StructTypeField {
371                identifier: field.identifier.clone(),
372                field_type: new_type,
373            };
374            new_fields.insert(name.clone(), new_field).unwrap();
375        }
376
377        let new_assigned_name =
378            Self::parameterized_name(&struct_type.assigned_name, &type_variables.variables());
379
380        let Type::Blueprint(blueprint) = current_self.unwrap() else {
381            panic!("must be blueprint");
382        };
383
384        let new_struct = NamedStructType {
385            name: struct_type.name.clone(),
386            assigned_name: new_assigned_name,
387            anon_struct_type: AnonymousStructType {
388                field_name_sorted_fields: new_fields,
389            },
390            module_path: struct_type.module_path.clone(),
391            instantiated_type_parameters: type_variables
392                .type_variables
393                .values()
394                .cloned()
395                .collect::<Vec<_>>(),
396            blueprint_info: Some(blueprint.info()),
397        };
398
399        Ok((was_any_replaced, Type::NamedStruct(new_struct)))
400    }
401}