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