sway_core/abi_generation/
fuel_abi.rs

1use fuel_abi_types::abi::program::{
2    self as program_abi, ConcreteTypeId, MetadataTypeId, TypeConcreteDeclaration,
3};
4use sha2::{Digest, Sha256};
5use std::collections::{HashMap, HashSet};
6use sway_error::handler::{ErrorEmitted, Handler};
7use sway_types::Span;
8
9use crate::{
10    language::ty::{TyFunctionDecl, TyProgram, TyProgramKind},
11    transform::AttributesMap,
12    Engines, TypeId, TypeInfo, TypeParameter,
13};
14
15use super::abi_str::AbiStrContext;
16
17pub struct AbiContext<'a> {
18    pub program: &'a TyProgram,
19    pub abi_with_callpaths: bool,
20    pub type_ids_to_full_type_str: HashMap<String, String>,
21}
22
23impl AbiContext<'_> {
24    fn to_str_context(&self) -> AbiStrContext {
25        AbiStrContext {
26            program_name: self.program.namespace.current_package_name().to_string(),
27            abi_with_callpaths: self.abi_with_callpaths,
28            abi_with_fully_specified_types: false,
29            abi_root_type_without_generic_type_parameters: true,
30        }
31    }
32}
33
34impl TypeId {
35    fn get_abi_type_field_and_concrete_id(
36        &self,
37        handler: &Handler,
38        ctx: &mut AbiContext,
39        engines: &Engines,
40        resolved_type_id: TypeId,
41    ) -> Result<(String, ConcreteTypeId), ErrorEmitted> {
42        let type_str = self.get_abi_type_str(
43            &AbiStrContext {
44                program_name: ctx.program.namespace.current_package_name().to_string(),
45                abi_with_callpaths: true,
46                abi_with_fully_specified_types: true,
47                abi_root_type_without_generic_type_parameters: false,
48            },
49            engines,
50            resolved_type_id,
51        );
52        let mut hasher = Sha256::new();
53        hasher.update(type_str.clone());
54        let result = hasher.finalize();
55        let type_id = format!("{:x}", result);
56
57        if let Some(old_type_str) = ctx
58            .type_ids_to_full_type_str
59            .insert(type_id.clone(), type_str.clone())
60        {
61            if old_type_str != type_str {
62                return Err(
63                    handler.emit_err(sway_error::error::CompileError::ABIHashCollision {
64                        span: Span::dummy(),
65                        hash: type_id,
66                        first_type: old_type_str,
67                        second_type: type_str,
68                    }),
69                );
70            }
71        }
72
73        Ok((type_str, ConcreteTypeId(type_id)))
74    }
75}
76
77pub fn generate_program_abi(
78    handler: &Handler,
79    ctx: &mut AbiContext,
80    engines: &Engines,
81    encoding_version: program_abi::Version,
82    spec_version: program_abi::Version,
83) -> Result<program_abi::ProgramABI, ErrorEmitted> {
84    let decl_engine = engines.de();
85    let metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration> = &mut vec![];
86    let concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration> = &mut vec![];
87    let mut program_abi = match &ctx.program.kind {
88        TyProgramKind::Contract { abi_entries, .. } => {
89            let functions = abi_entries
90                .iter()
91                .map(|x| {
92                    let fn_decl = decl_engine.get_function(x);
93                    fn_decl.generate_abi_function(
94                        handler,
95                        ctx,
96                        engines,
97                        metadata_types,
98                        concrete_types,
99                    )
100                })
101                .collect::<Result<Vec<_>, _>>()?;
102            let logged_types =
103                generate_logged_types(handler, ctx, engines, metadata_types, concrete_types)?;
104            let messages_types =
105                generate_messages_types(handler, ctx, engines, metadata_types, concrete_types)?;
106            let configurables =
107                generate_configurables(handler, ctx, engines, metadata_types, concrete_types)?;
108            program_abi::ProgramABI {
109                program_type: "contract".to_string(),
110                spec_version,
111                encoding_version,
112                metadata_types: metadata_types.to_vec(),
113                concrete_types: concrete_types.to_vec(),
114                functions,
115                logged_types: Some(logged_types),
116                messages_types: Some(messages_types),
117                configurables: Some(configurables),
118            }
119        }
120        TyProgramKind::Script { main_function, .. } => {
121            let main_function = decl_engine.get_function(main_function);
122            let functions = vec![main_function.generate_abi_function(
123                handler,
124                ctx,
125                engines,
126                metadata_types,
127                concrete_types,
128            )?];
129            let logged_types =
130                generate_logged_types(handler, ctx, engines, metadata_types, concrete_types)?;
131            let messages_types =
132                generate_messages_types(handler, ctx, engines, metadata_types, concrete_types)?;
133            let configurables =
134                generate_configurables(handler, ctx, engines, metadata_types, concrete_types)?;
135            program_abi::ProgramABI {
136                program_type: "script".to_string(),
137                spec_version,
138                encoding_version,
139                metadata_types: metadata_types.to_vec(),
140                concrete_types: concrete_types.to_vec(),
141                functions,
142                logged_types: Some(logged_types),
143                messages_types: Some(messages_types),
144                configurables: Some(configurables),
145            }
146        }
147        TyProgramKind::Predicate { main_function, .. } => {
148            let main_function = decl_engine.get_function(main_function);
149            let functions = vec![main_function.generate_abi_function(
150                handler,
151                ctx,
152                engines,
153                metadata_types,
154                concrete_types,
155            )?];
156            let logged_types =
157                generate_logged_types(handler, ctx, engines, metadata_types, concrete_types)?;
158            let messages_types =
159                generate_messages_types(handler, ctx, engines, metadata_types, concrete_types)?;
160            let configurables =
161                generate_configurables(handler, ctx, engines, metadata_types, concrete_types)?;
162            program_abi::ProgramABI {
163                program_type: "predicate".to_string(),
164                spec_version,
165                encoding_version,
166                metadata_types: metadata_types.to_vec(),
167                concrete_types: concrete_types.to_vec(),
168                functions,
169                logged_types: Some(logged_types),
170                messages_types: Some(messages_types),
171                configurables: Some(configurables),
172            }
173        }
174        TyProgramKind::Library { .. } => {
175            let logged_types =
176                generate_logged_types(handler, ctx, engines, metadata_types, concrete_types)?;
177            let messages_types =
178                generate_messages_types(handler, ctx, engines, metadata_types, concrete_types)?;
179
180            program_abi::ProgramABI {
181                program_type: "library".to_string(),
182                spec_version,
183                encoding_version,
184                metadata_types: metadata_types.to_vec(),
185                concrete_types: concrete_types.to_vec(),
186                functions: vec![],
187                logged_types: Some(logged_types),
188                messages_types: Some(messages_types),
189                configurables: None,
190            }
191        }
192    };
193
194    standardize_json_abi_types(&mut program_abi);
195
196    Ok(program_abi)
197}
198
199/// Standardize the JSON ABI data structure by eliminating duplicate types. This is an iterative
200/// process because every time two types are merged, new opportunities for more merging arise.
201fn standardize_json_abi_types(json_abi_program: &mut program_abi::ProgramABI) {
202    // Dedup TypeMetadataDeclaration
203    loop {
204        // If type with id_1 is a duplicate of type with id_2, then keep track of the mapping
205        // between id_1 and id_2 in the HashMap below.
206        let mut old_to_new_id: HashMap<MetadataTypeId, program_abi::TypeId> = HashMap::new();
207
208        // A vector containing unique `program_abi::TypeMetadataDeclaration`s.
209        //
210        // Two `program_abi::TypeMetadataDeclaration` are deemed the same if the have the same
211        // `type_field`, `components`, and `type_parameters` (even if their `type_id`s are
212        // different).
213        let mut deduped_types: Vec<program_abi::TypeMetadataDeclaration> = Vec::new();
214
215        // Insert values in `deduped_types` if they haven't been inserted before. Otherwise, create
216        // an appropriate mapping between type IDs in the HashMap `old_to_new_id`.
217        for decl in &json_abi_program.metadata_types {
218            // First replace metadata_type_id with concrete_type_id when possible
219            if let Some(ty) = json_abi_program.concrete_types.iter().find(|d| {
220                d.type_field == decl.type_field
221                    && decl.components.is_none()
222                    && decl.type_parameters.is_none()
223            }) {
224                old_to_new_id.insert(
225                    decl.metadata_type_id.clone(),
226                    program_abi::TypeId::Concrete(ty.concrete_type_id.clone()),
227                );
228            } else {
229                // Second replace metadata_type_id with metadata_type_id when possible
230                if let Some(ty) = deduped_types.iter().find(|d| {
231                    d.type_field == decl.type_field
232                        && d.components == decl.components
233                        && d.type_parameters == decl.type_parameters
234                }) {
235                    old_to_new_id.insert(
236                        decl.metadata_type_id.clone(),
237                        program_abi::TypeId::Metadata(ty.metadata_type_id.clone()),
238                    );
239                } else {
240                    deduped_types.push(decl.clone());
241                }
242            }
243        }
244
245        // Nothing to do if the hash map is empty as there are not merge opportunities. We can now
246        // exit the loop.
247        if old_to_new_id.is_empty() {
248            break;
249        }
250
251        json_abi_program.metadata_types = deduped_types;
252
253        update_all_types(json_abi_program, &old_to_new_id);
254    }
255
256    // Dedup TypeConcreteDeclaration
257    let mut concrete_declarations_map: HashMap<ConcreteTypeId, TypeConcreteDeclaration> =
258        HashMap::new();
259    for decl in &json_abi_program.concrete_types {
260        concrete_declarations_map.insert(decl.concrete_type_id.clone(), decl.clone());
261    }
262    json_abi_program.concrete_types = concrete_declarations_map.values().cloned().collect();
263
264    // Sort the `program_abi::TypeMetadataDeclaration`s
265    json_abi_program
266        .metadata_types
267        .sort_by(|t1, t2| t1.type_field.cmp(&t2.type_field));
268
269    // Sort the `program_abi::TypeConcreteDeclaration`s
270    json_abi_program
271        .concrete_types
272        .sort_by(|t1, t2| t1.type_field.cmp(&t2.type_field));
273
274    // Standardize IDs (i.e. change them to 0,1,2,... according to the alphabetical order above
275    let mut old_to_new_id: HashMap<MetadataTypeId, program_abi::TypeId> = HashMap::new();
276    for (ix, decl) in json_abi_program.metadata_types.iter_mut().enumerate() {
277        old_to_new_id.insert(
278            decl.metadata_type_id.clone(),
279            program_abi::TypeId::Metadata(MetadataTypeId(ix)),
280        );
281        decl.metadata_type_id = MetadataTypeId(ix);
282    }
283
284    update_all_types(json_abi_program, &old_to_new_id);
285}
286
287/// Recursively updates the type IDs used in a program_abi::ProgramABI
288fn update_all_types(
289    json_abi_program: &mut program_abi::ProgramABI,
290    old_to_new_id: &HashMap<MetadataTypeId, program_abi::TypeId>,
291) {
292    // Update all `program_abi::TypeMetadataDeclaration`
293    for decl in &mut json_abi_program.metadata_types {
294        update_json_type_metadata_declaration(decl, old_to_new_id);
295    }
296
297    // Update all `program_abi::TypeConcreteDeclaration`
298    for decl in &mut json_abi_program.concrete_types {
299        update_json_type_concrete_declaration(decl, old_to_new_id);
300    }
301}
302
303/// Recursively updates the type IDs used in a `program_abi::TypeApplication` given a HashMap from
304/// old to new IDs
305fn update_json_type_application(
306    type_application: &mut program_abi::TypeApplication,
307    old_to_new_id: &HashMap<MetadataTypeId, program_abi::TypeId>,
308) {
309    if let fuel_abi_types::abi::program::TypeId::Metadata(metadata_type_id) =
310        &type_application.type_id
311    {
312        if let Some(new_id) = old_to_new_id.get(metadata_type_id) {
313            type_application.type_id = new_id.clone();
314        }
315    }
316
317    if let Some(args) = &mut type_application.type_arguments {
318        for arg in args.iter_mut() {
319            update_json_type_application(arg, old_to_new_id);
320        }
321    }
322}
323
324/// Recursively updates the metadata type IDs used in a `program_abi::TypeMetadataDeclaration` given a HashMap from
325/// old to new IDs
326fn update_json_type_metadata_declaration(
327    type_declaration: &mut program_abi::TypeMetadataDeclaration,
328    old_to_new_id: &HashMap<MetadataTypeId, program_abi::TypeId>,
329) {
330    if let Some(params) = &mut type_declaration.type_parameters {
331        for param in params.iter_mut() {
332            if let Some(fuel_abi_types::abi::program::TypeId::Metadata(new_id)) =
333                old_to_new_id.get(param)
334            {
335                *param = new_id.clone();
336            }
337        }
338    }
339
340    if let Some(components) = &mut type_declaration.components {
341        for component in components.iter_mut() {
342            update_json_type_application(component, old_to_new_id);
343        }
344    }
345}
346
347/// RUpdates the metadata type IDs used in a `program_abi::TypeConcreteDeclaration` given a HashMap from
348/// old to new IDs
349fn update_json_type_concrete_declaration(
350    type_declaration: &mut program_abi::TypeConcreteDeclaration,
351    old_to_new_id: &HashMap<MetadataTypeId, program_abi::TypeId>,
352) {
353    if let Some(metadata_type_id) = &mut type_declaration.metadata_type_id {
354        if let Some(fuel_abi_types::abi::program::TypeId::Metadata(new_id)) =
355            old_to_new_id.get(metadata_type_id)
356        {
357            *metadata_type_id = new_id.clone();
358        }
359    }
360}
361
362fn generate_concrete_type_declaration(
363    handler: &Handler,
364    ctx: &mut AbiContext,
365    engines: &Engines,
366    metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
367    concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
368    type_id: TypeId,
369    resolved_type_id: TypeId,
370) -> Result<ConcreteTypeId, ErrorEmitted> {
371    let mut new_metadata_types_to_add = Vec::<program_abi::TypeMetadataDeclaration>::new();
372    let type_metadata_decl = program_abi::TypeMetadataDeclaration {
373        metadata_type_id: MetadataTypeId(type_id.index()),
374        type_field: type_id.get_abi_type_str(&ctx.to_str_context(), engines, resolved_type_id),
375        components: type_id.get_abi_type_components(
376            handler,
377            ctx,
378            engines,
379            metadata_types,
380            concrete_types,
381            resolved_type_id,
382            &mut new_metadata_types_to_add,
383        )?,
384        type_parameters: type_id.get_abi_type_parameters(
385            handler,
386            ctx,
387            engines,
388            metadata_types,
389            concrete_types,
390            resolved_type_id,
391            &mut new_metadata_types_to_add,
392        )?,
393    };
394
395    let metadata_type_id = if type_metadata_decl.type_parameters.is_some()
396        || type_metadata_decl.components.is_some()
397    {
398        Some(type_metadata_decl.metadata_type_id.clone())
399    } else {
400        None
401    };
402    let type_arguments = if type_metadata_decl.type_parameters.is_some() {
403        type_id.get_abi_type_arguments_as_concrete_type_ids(
404            handler,
405            ctx,
406            engines,
407            metadata_types,
408            concrete_types,
409            resolved_type_id,
410        )?
411    } else {
412        None
413    };
414
415    metadata_types.push(type_metadata_decl);
416    metadata_types.extend(new_metadata_types_to_add);
417
418    let (type_field, concrete_type_id) =
419        type_id.get_abi_type_field_and_concrete_id(handler, ctx, engines, resolved_type_id)?;
420    let concrete_type_decl = TypeConcreteDeclaration {
421        type_field,
422        concrete_type_id: concrete_type_id.clone(),
423        metadata_type_id,
424        type_arguments,
425    };
426
427    concrete_types.push(concrete_type_decl);
428
429    Ok(concrete_type_id)
430}
431
432#[allow(clippy::too_many_arguments)]
433fn generate_type_metadata_declaration(
434    handler: &Handler,
435    ctx: &mut AbiContext,
436    engines: &Engines,
437    metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
438    concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
439    type_id: TypeId,
440    resolved_type_id: TypeId,
441    metadata_types_to_add: &mut Vec<program_abi::TypeMetadataDeclaration>,
442) -> Result<(), ErrorEmitted> {
443    let mut new_metadata_types_to_add = Vec::<program_abi::TypeMetadataDeclaration>::new();
444    let components = type_id.get_abi_type_components(
445        handler,
446        ctx,
447        engines,
448        metadata_types,
449        concrete_types,
450        resolved_type_id,
451        &mut new_metadata_types_to_add,
452    )?;
453    let type_parameters = type_id.get_abi_type_parameters(
454        handler,
455        ctx,
456        engines,
457        metadata_types,
458        concrete_types,
459        resolved_type_id,
460        &mut new_metadata_types_to_add,
461    )?;
462    let type_metadata_decl = program_abi::TypeMetadataDeclaration {
463        metadata_type_id: MetadataTypeId(type_id.index()),
464        type_field: type_id.get_abi_type_str(&ctx.to_str_context(), engines, resolved_type_id),
465        components,
466        type_parameters,
467    };
468
469    metadata_types_to_add.push(type_metadata_decl.clone());
470    metadata_types_to_add.extend(new_metadata_types_to_add);
471
472    Ok(())
473}
474
475fn generate_logged_types(
476    handler: &Handler,
477    ctx: &mut AbiContext,
478    engines: &Engines,
479    metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
480    concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
481) -> Result<Vec<program_abi::LoggedType>, ErrorEmitted> {
482    // Generate the JSON data for the logged types
483    let mut log_ids: HashSet<u64> = HashSet::default();
484    Ok(ctx
485        .program
486        .logged_types
487        .iter()
488        .map(|(log_id, type_id)| {
489            let log_id = log_id.hash_id;
490            if log_ids.contains(&log_id) {
491                Ok(None)
492            } else {
493                log_ids.insert(log_id);
494                Ok(Some(program_abi::LoggedType {
495                    log_id: log_id.to_string(),
496                    concrete_type_id: generate_concrete_type_declaration(
497                        handler,
498                        ctx,
499                        engines,
500                        metadata_types,
501                        concrete_types,
502                        *type_id,
503                        *type_id,
504                    )?,
505                }))
506            }
507        })
508        .collect::<Result<Vec<_>, _>>()?
509        .into_iter()
510        .flatten()
511        .collect())
512}
513
514fn generate_messages_types(
515    handler: &Handler,
516    ctx: &mut AbiContext,
517    engines: &Engines,
518    metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
519    concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
520) -> Result<Vec<program_abi::MessageType>, ErrorEmitted> {
521    // Generate the JSON data for the messages types
522    ctx.program
523        .messages_types
524        .iter()
525        .map(|(message_id, type_id)| {
526            Ok(program_abi::MessageType {
527                message_id: (**message_id as u64).to_string(),
528                concrete_type_id: generate_concrete_type_declaration(
529                    handler,
530                    ctx,
531                    engines,
532                    metadata_types,
533                    concrete_types,
534                    *type_id,
535                    *type_id,
536                )?,
537            })
538        })
539        .collect::<Result<Vec<_>, _>>()
540}
541
542fn generate_configurables(
543    handler: &Handler,
544    ctx: &mut AbiContext,
545    engines: &Engines,
546    metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
547    concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
548) -> Result<Vec<program_abi::Configurable>, ErrorEmitted> {
549    // Generate the JSON data for the configurables types
550    ctx.program
551        .configurables
552        .iter()
553        .map(|decl| {
554            Ok(program_abi::Configurable {
555                name: decl.call_path.suffix.to_string(),
556                concrete_type_id: generate_concrete_type_declaration(
557                    handler,
558                    ctx,
559                    engines,
560                    metadata_types,
561                    concrete_types,
562                    decl.type_ascription.type_id,
563                    decl.type_ascription.type_id,
564                )?,
565                offset: 0,
566            })
567        })
568        .collect::<Result<Vec<_>, _>>()
569}
570
571impl TypeId {
572    /// Return the type parameters of a given (potentially generic) type while considering what it
573    /// actually resolves to. These parameters are essentially of type of `usize` which are
574    /// basically the IDs of some set of `program_abi::TypeMetadataDeclaration`s. The method below also
575    /// updates the provide list of `program_abi::TypeMetadataDeclaration`s  to add the newly discovered
576    /// types.
577    #[allow(clippy::too_many_arguments)]
578    pub(self) fn get_abi_type_parameters(
579        &self,
580        handler: &Handler,
581        ctx: &mut AbiContext,
582        engines: &Engines,
583        metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
584        concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
585        resolved_type_id: TypeId,
586        metadata_types_to_add: &mut Vec<program_abi::TypeMetadataDeclaration>,
587    ) -> Result<Option<Vec<MetadataTypeId>>, ErrorEmitted> {
588        match self.is_generic_parameter(engines, resolved_type_id) {
589            true => Ok(None),
590            false => resolved_type_id
591                .get_type_parameters(engines)
592                .map(|v| {
593                    v.iter()
594                        .map(|v| {
595                            v.get_abi_type_parameter(
596                                handler,
597                                ctx,
598                                engines,
599                                metadata_types,
600                                concrete_types,
601                                metadata_types_to_add,
602                            )
603                        })
604                        .collect::<Result<Vec<_>, _>>()
605                })
606                .map_or(Ok(None), |v| v.map(Some)),
607        }
608    }
609
610    /// Return the components of a given (potentially generic) type while considering what it
611    /// actually resolves to. These components are essentially of type of
612    /// `program_abi::TypeApplication`.  The method below also updates the provided list of
613    /// `program_abi::TypeMetadataDeclaration`s  to add the newly discovered types.
614    #[allow(clippy::too_many_arguments)]
615    pub(self) fn get_abi_type_components(
616        &self,
617        handler: &Handler,
618        ctx: &mut AbiContext,
619        engines: &Engines,
620        metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
621        concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
622        resolved_type_id: TypeId,
623        metadata_types_to_add: &mut Vec<program_abi::TypeMetadataDeclaration>,
624    ) -> Result<Option<Vec<program_abi::TypeApplication>>, ErrorEmitted> {
625        let type_engine = engines.te();
626        let decl_engine = engines.de();
627        Ok(match &*type_engine.get(*self) {
628            TypeInfo::Enum(decl_ref) => {
629                let decl = decl_engine.get_enum(decl_ref);
630
631                let mut new_metadata_types_to_add =
632                    Vec::<program_abi::TypeMetadataDeclaration>::new();
633                for x in decl.variants.iter() {
634                    generate_type_metadata_declaration(
635                        handler,
636                        ctx,
637                        engines,
638                        metadata_types,
639                        concrete_types,
640                        x.type_argument.initial_type_id,
641                        x.type_argument.type_id,
642                        &mut new_metadata_types_to_add,
643                    )?;
644                }
645
646                // Generate the JSON data for the enum. This is basically a list of
647                // `program_abi::TypeApplication`s
648                let components = decl
649                    .variants
650                    .iter()
651                    .map(|x| {
652                        Ok(program_abi::TypeApplication {
653                            name: x.name.to_string(),
654                            type_id: program_abi::TypeId::Metadata(MetadataTypeId(
655                                x.type_argument.initial_type_id.index(),
656                            )),
657                            type_arguments: x
658                                .type_argument
659                                .initial_type_id
660                                .get_abi_type_arguments(
661                                    handler,
662                                    ctx,
663                                    engines,
664                                    metadata_types,
665                                    concrete_types,
666                                    x.type_argument.type_id,
667                                    &mut new_metadata_types_to_add,
668                                )?,
669                        })
670                    })
671                    .collect::<Result<Vec<_>, _>>()?;
672
673                if components.is_empty() {
674                    None
675                } else {
676                    metadata_types_to_add.extend(new_metadata_types_to_add);
677                    Some(components)
678                }
679            }
680            TypeInfo::Struct(decl_ref) => {
681                let decl = decl_engine.get_struct(decl_ref);
682
683                let mut new_metadata_types_to_add =
684                    Vec::<program_abi::TypeMetadataDeclaration>::new();
685                for x in decl.fields.iter() {
686                    generate_type_metadata_declaration(
687                        handler,
688                        ctx,
689                        engines,
690                        metadata_types,
691                        concrete_types,
692                        x.type_argument.initial_type_id,
693                        x.type_argument.type_id,
694                        &mut new_metadata_types_to_add,
695                    )?;
696                }
697
698                // Generate the JSON data for the struct. This is basically a list of
699                // `program_abi::TypeApplication`s
700                let components = decl
701                    .fields
702                    .iter()
703                    .map(|x| {
704                        Ok(program_abi::TypeApplication {
705                            name: x.name.to_string(),
706                            type_id: program_abi::TypeId::Metadata(MetadataTypeId(
707                                x.type_argument.initial_type_id.index(),
708                            )),
709                            type_arguments: x
710                                .type_argument
711                                .initial_type_id
712                                .get_abi_type_arguments(
713                                    handler,
714                                    ctx,
715                                    engines,
716                                    metadata_types,
717                                    concrete_types,
718                                    x.type_argument.type_id,
719                                    &mut new_metadata_types_to_add,
720                                )?,
721                        })
722                    })
723                    .collect::<Result<Vec<_>, _>>()?;
724
725                if components.is_empty() {
726                    None
727                } else {
728                    metadata_types_to_add.extend(new_metadata_types_to_add);
729                    Some(components)
730                }
731            }
732            TypeInfo::Array(..) => {
733                if let TypeInfo::Array(elem_ty, _) = &*type_engine.get(resolved_type_id) {
734                    generate_type_metadata_declaration(
735                        handler,
736                        ctx,
737                        engines,
738                        metadata_types,
739                        concrete_types,
740                        elem_ty.initial_type_id,
741                        elem_ty.type_id,
742                        metadata_types_to_add,
743                    )?;
744
745                    // Generate the JSON data for the array. This is basically a single
746                    // `program_abi::TypeApplication` for the array element type
747                    Some(vec![program_abi::TypeApplication {
748                        name: "__array_element".to_string(),
749                        type_id: program_abi::TypeId::Metadata(MetadataTypeId(
750                            elem_ty.initial_type_id.index(),
751                        )),
752                        type_arguments: elem_ty.initial_type_id.get_abi_type_arguments(
753                            handler,
754                            ctx,
755                            engines,
756                            metadata_types,
757                            concrete_types,
758                            elem_ty.type_id,
759                            metadata_types_to_add,
760                        )?,
761                    }])
762                } else {
763                    unreachable!();
764                }
765            }
766            TypeInfo::Slice(..) => {
767                if let TypeInfo::Slice(elem_ty) = &*type_engine.get(resolved_type_id) {
768                    generate_type_metadata_declaration(
769                        handler,
770                        ctx,
771                        engines,
772                        metadata_types,
773                        concrete_types,
774                        elem_ty.initial_type_id,
775                        elem_ty.type_id,
776                        metadata_types_to_add,
777                    )?;
778
779                    // Generate the JSON data for the array. This is basically a single
780                    // `program_abi::TypeApplication` for the array element type
781                    Some(vec![program_abi::TypeApplication {
782                        name: "__slice_element".to_string(),
783                        type_id: program_abi::TypeId::Metadata(MetadataTypeId(
784                            elem_ty.initial_type_id.index(),
785                        )),
786                        type_arguments: elem_ty.initial_type_id.get_abi_type_arguments(
787                            handler,
788                            ctx,
789                            engines,
790                            metadata_types,
791                            concrete_types,
792                            elem_ty.type_id,
793                            metadata_types_to_add,
794                        )?,
795                    }])
796                } else {
797                    unreachable!();
798                }
799            }
800            TypeInfo::Tuple(_) => {
801                if let TypeInfo::Tuple(fields) = &*type_engine.get(resolved_type_id) {
802                    let mut new_metadata_types_to_add =
803                        Vec::<program_abi::TypeMetadataDeclaration>::new();
804                    for x in fields.iter() {
805                        generate_type_metadata_declaration(
806                            handler,
807                            ctx,
808                            engines,
809                            metadata_types,
810                            concrete_types,
811                            x.initial_type_id,
812                            x.type_id,
813                            &mut new_metadata_types_to_add,
814                        )?;
815                    }
816
817                    // Generate the JSON data for the tuple. This is basically a list of
818                    // `program_abi::TypeApplication`s
819                    let components = fields
820                        .iter()
821                        .map(|x| {
822                            Ok(program_abi::TypeApplication {
823                                name: "__tuple_element".to_string(),
824                                type_id: program_abi::TypeId::Metadata(MetadataTypeId(
825                                    x.initial_type_id.index(),
826                                )),
827                                type_arguments: x.initial_type_id.get_abi_type_arguments(
828                                    handler,
829                                    ctx,
830                                    engines,
831                                    metadata_types,
832                                    concrete_types,
833                                    x.type_id,
834                                    metadata_types_to_add,
835                                )?,
836                            })
837                        })
838                        .collect::<Result<Vec<_>, _>>()?;
839                    if components.is_empty() {
840                        None
841                    } else {
842                        metadata_types_to_add.extend(new_metadata_types_to_add);
843                        Some(components)
844                    }
845                } else {
846                    unreachable!()
847                }
848            }
849            TypeInfo::Custom { type_arguments, .. } => {
850                if !self.is_generic_parameter(engines, resolved_type_id) {
851                    for (v, p) in type_arguments.clone().unwrap_or_default().iter().zip(
852                        resolved_type_id
853                            .get_type_parameters(engines)
854                            .unwrap_or_default()
855                            .iter(),
856                    ) {
857                        generate_type_metadata_declaration(
858                            handler,
859                            ctx,
860                            engines,
861                            metadata_types,
862                            concrete_types,
863                            v.initial_type_id,
864                            p.type_id,
865                            metadata_types_to_add,
866                        )?;
867                    }
868                    resolved_type_id.get_abi_type_components(
869                        handler,
870                        ctx,
871                        engines,
872                        metadata_types,
873                        concrete_types,
874                        resolved_type_id,
875                        metadata_types_to_add,
876                    )?
877                } else {
878                    None
879                }
880            }
881            TypeInfo::Alias { .. } => {
882                if let TypeInfo::Alias { ty, .. } = &*type_engine.get(resolved_type_id) {
883                    ty.initial_type_id.get_abi_type_components(
884                        handler,
885                        ctx,
886                        engines,
887                        metadata_types,
888                        concrete_types,
889                        ty.type_id,
890                        metadata_types_to_add,
891                    )?
892                } else {
893                    None
894                }
895            }
896            TypeInfo::UnknownGeneric { .. } => {
897                // avoid infinite recursion
898                if *self == resolved_type_id {
899                    None
900                } else {
901                    resolved_type_id.get_abi_type_components(
902                        handler,
903                        ctx,
904                        engines,
905                        metadata_types,
906                        concrete_types,
907                        resolved_type_id,
908                        metadata_types_to_add,
909                    )?
910                }
911            }
912            _ => None,
913        })
914    }
915
916    /// Return the type arguments of a given (potentially generic) type while considering what it
917    /// actually resolves to. These arguments are essentially of type of
918    /// `program_abi::TypeApplication`. The method below also updates the provided list of
919    /// `program_abi::TypeMetadataDeclaration`s  to add the newly discovered types.
920    #[allow(clippy::too_many_arguments)]
921    pub(self) fn get_abi_type_arguments(
922        &self,
923        handler: &Handler,
924        ctx: &mut AbiContext,
925        engines: &Engines,
926        metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
927        concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
928        resolved_type_id: TypeId,
929        metadata_types_to_add: &mut Vec<program_abi::TypeMetadataDeclaration>,
930    ) -> Result<Option<Vec<program_abi::TypeApplication>>, ErrorEmitted> {
931        let type_engine = engines.te();
932        let decl_engine = engines.de();
933        let resolved_params = resolved_type_id.get_type_parameters(engines);
934        Ok(match &*type_engine.get(*self) {
935            TypeInfo::Custom {
936                type_arguments: Some(type_arguments),
937                ..
938            } => (!type_arguments.is_empty()).then_some({
939                let resolved_params = resolved_params.unwrap_or_default();
940
941                for (v, p) in type_arguments.iter().zip(resolved_params.iter()) {
942                    generate_type_metadata_declaration(
943                        handler,
944                        ctx,
945                        engines,
946                        metadata_types,
947                        concrete_types,
948                        v.type_id,
949                        p.type_id,
950                        metadata_types_to_add,
951                    )?;
952                }
953
954                type_arguments
955                    .iter()
956                    .zip(resolved_params.iter())
957                    .map(|(arg, p)| {
958                        Ok(program_abi::TypeApplication {
959                            name: "".to_string(),
960                            type_id: program_abi::TypeId::Metadata(MetadataTypeId(
961                                arg.initial_type_id.index(),
962                            )),
963                            type_arguments: arg.initial_type_id.get_abi_type_arguments(
964                                handler,
965                                ctx,
966                                engines,
967                                metadata_types,
968                                concrete_types,
969                                p.type_id,
970                                metadata_types_to_add,
971                            )?,
972                        })
973                    })
974                    .collect::<Result<Vec<_>, _>>()?
975            }),
976            TypeInfo::Enum(decl_ref) => {
977                let decl = decl_engine.get_enum(decl_ref);
978
979                let mut new_metadata_types_to_add =
980                    Vec::<program_abi::TypeMetadataDeclaration>::new();
981                for v in decl.type_parameters.iter() {
982                    generate_type_metadata_declaration(
983                        handler,
984                        ctx,
985                        engines,
986                        metadata_types,
987                        concrete_types,
988                        v.type_id,
989                        v.type_id,
990                        &mut new_metadata_types_to_add,
991                    )?;
992                }
993
994                let type_arguments = decl
995                    .type_parameters
996                    .iter()
997                    .map(|arg| {
998                        Ok(program_abi::TypeApplication {
999                            name: "".to_string(),
1000                            type_id: program_abi::TypeId::Metadata(MetadataTypeId(
1001                                arg.type_id.index(),
1002                            )),
1003                            type_arguments: arg.type_id.get_abi_type_arguments(
1004                                handler,
1005                                ctx,
1006                                engines,
1007                                metadata_types,
1008                                concrete_types,
1009                                arg.type_id,
1010                                &mut new_metadata_types_to_add,
1011                            )?,
1012                        })
1013                    })
1014                    .collect::<Result<Vec<_>, _>>()?;
1015
1016                if type_arguments.is_empty() {
1017                    None
1018                } else {
1019                    metadata_types_to_add.extend(new_metadata_types_to_add);
1020                    Some(type_arguments)
1021                }
1022            }
1023
1024            TypeInfo::Struct(decl_ref) => {
1025                let decl = decl_engine.get_struct(decl_ref);
1026
1027                let mut new_metadata_types_to_add =
1028                    Vec::<program_abi::TypeMetadataDeclaration>::new();
1029                for v in decl.type_parameters.iter() {
1030                    generate_type_metadata_declaration(
1031                        handler,
1032                        ctx,
1033                        engines,
1034                        metadata_types,
1035                        concrete_types,
1036                        v.type_id,
1037                        v.type_id,
1038                        &mut new_metadata_types_to_add,
1039                    )?;
1040                }
1041
1042                let type_arguments = decl
1043                    .type_parameters
1044                    .iter()
1045                    .map(|arg| {
1046                        Ok(program_abi::TypeApplication {
1047                            name: "".to_string(),
1048                            type_id: program_abi::TypeId::Metadata(MetadataTypeId(
1049                                arg.type_id.index(),
1050                            )),
1051                            type_arguments: arg.type_id.get_abi_type_arguments(
1052                                handler,
1053                                ctx,
1054                                engines,
1055                                metadata_types,
1056                                concrete_types,
1057                                arg.type_id,
1058                                &mut new_metadata_types_to_add,
1059                            )?,
1060                        })
1061                    })
1062                    .collect::<Result<Vec<_>, _>>()?;
1063
1064                if type_arguments.is_empty() {
1065                    None
1066                } else {
1067                    metadata_types_to_add.extend(new_metadata_types_to_add);
1068                    Some(type_arguments)
1069                }
1070            }
1071            _ => None,
1072        })
1073    }
1074
1075    /// Return the type arguments of a given (potentially generic) type while considering what it
1076    /// actually resolves to. These arguments are essentially of type of
1077    /// `program_abi::TypeApplication`. The method below also updates the provided list of
1078    /// `program_abi::TypeMetadataDeclaration`s  to add the newly discovered types.
1079    pub(self) fn get_abi_type_arguments_as_concrete_type_ids(
1080        &self,
1081        handler: &Handler,
1082        ctx: &mut AbiContext,
1083        engines: &Engines,
1084        metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
1085        concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
1086        resolved_type_id: TypeId,
1087    ) -> Result<Option<Vec<program_abi::ConcreteTypeId>>, ErrorEmitted> {
1088        let type_engine = engines.te();
1089        let decl_engine = engines.de();
1090        let resolved_params = resolved_type_id.get_type_parameters(engines);
1091        Ok(match &*type_engine.get(*self) {
1092            TypeInfo::Custom {
1093                type_arguments: Some(type_arguments),
1094                ..
1095            } => (!type_arguments.is_empty()).then_some({
1096                let resolved_params = resolved_params.unwrap_or_default();
1097                type_arguments
1098                    .iter()
1099                    .zip(resolved_params.iter())
1100                    .map(|(arg, p)| {
1101                        generate_concrete_type_declaration(
1102                            handler,
1103                            ctx,
1104                            engines,
1105                            metadata_types,
1106                            concrete_types,
1107                            arg.initial_type_id,
1108                            p.type_id,
1109                        )
1110                    })
1111                    .collect::<Result<Vec<_>, _>>()?
1112            }),
1113            TypeInfo::Enum(decl_ref) => {
1114                let decl = decl_engine.get_enum(decl_ref);
1115                Some(
1116                    decl.type_parameters
1117                        .iter()
1118                        .map(|arg| {
1119                            generate_concrete_type_declaration(
1120                                handler,
1121                                ctx,
1122                                engines,
1123                                metadata_types,
1124                                concrete_types,
1125                                arg.type_id,
1126                                arg.type_id,
1127                            )
1128                        })
1129                        .collect::<Result<Vec<_>, _>>()?,
1130                )
1131            }
1132            TypeInfo::Struct(decl_ref) => {
1133                let decl = decl_engine.get_struct(decl_ref);
1134                Some(
1135                    decl.type_parameters
1136                        .iter()
1137                        .map(|arg| {
1138                            generate_concrete_type_declaration(
1139                                handler,
1140                                ctx,
1141                                engines,
1142                                metadata_types,
1143                                concrete_types,
1144                                arg.type_id,
1145                                arg.type_id,
1146                            )
1147                        })
1148                        .collect::<Result<Vec<_>, _>>()?,
1149                )
1150            }
1151            _ => None,
1152        })
1153    }
1154}
1155
1156impl TyFunctionDecl {
1157    pub(self) fn generate_abi_function(
1158        &self,
1159        handler: &Handler,
1160        ctx: &mut AbiContext,
1161        engines: &Engines,
1162        metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
1163        concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
1164    ) -> Result<program_abi::ABIFunction, ErrorEmitted> {
1165        // Generate the JSON data for the function
1166        Ok(program_abi::ABIFunction {
1167            name: self.name.as_str().to_string(),
1168            inputs: self
1169                .parameters
1170                .iter()
1171                .map(|x| {
1172                    Ok(program_abi::TypeConcreteParameter {
1173                        name: x.name.to_string(),
1174                        concrete_type_id: generate_concrete_type_declaration(
1175                            handler,
1176                            ctx,
1177                            engines,
1178                            metadata_types,
1179                            concrete_types,
1180                            x.type_argument.initial_type_id,
1181                            x.type_argument.type_id,
1182                        )?,
1183                    })
1184                })
1185                .collect::<Result<Vec<_>, _>>()?,
1186            output: generate_concrete_type_declaration(
1187                handler,
1188                ctx,
1189                engines,
1190                metadata_types,
1191                concrete_types,
1192                self.return_type.initial_type_id,
1193                self.return_type.type_id,
1194            )?,
1195            attributes: generate_attributes_map(&self.attributes),
1196        })
1197    }
1198}
1199
1200fn generate_attributes_map(attr_map: &AttributesMap) -> Option<Vec<program_abi::Attribute>> {
1201    if attr_map.is_empty() {
1202        None
1203    } else {
1204        Some(
1205            attr_map
1206                .iter()
1207                .flat_map(|(_attr_kind, attrs)| {
1208                    attrs.iter().map(|attr| program_abi::Attribute {
1209                        name: attr.name.to_string(),
1210                        arguments: attr.args.iter().map(|arg| arg.name.to_string()).collect(),
1211                    })
1212                })
1213                .collect(),
1214        )
1215    }
1216}
1217
1218impl TypeParameter {
1219    /// Returns the initial type ID of a TypeParameter. Also updates the provided list of types to
1220    /// append the current TypeParameter as a `program_abi::TypeMetadataDeclaration`.
1221    pub(self) fn get_abi_type_parameter(
1222        &self,
1223        handler: &Handler,
1224        ctx: &mut AbiContext,
1225        engines: &Engines,
1226        metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
1227        concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
1228        metadata_types_to_add: &mut Vec<program_abi::TypeMetadataDeclaration>,
1229    ) -> Result<MetadataTypeId, ErrorEmitted> {
1230        let type_id = MetadataTypeId(self.initial_type_id.index());
1231        let type_parameter = program_abi::TypeMetadataDeclaration {
1232            metadata_type_id: type_id.clone(),
1233            type_field: self.initial_type_id.get_abi_type_str(
1234                &ctx.to_str_context(),
1235                engines,
1236                self.type_id,
1237            ),
1238            components: self.initial_type_id.get_abi_type_components(
1239                handler,
1240                ctx,
1241                engines,
1242                metadata_types,
1243                concrete_types,
1244                self.type_id,
1245                metadata_types_to_add,
1246            )?,
1247            type_parameters: None,
1248        };
1249        metadata_types_to_add.push(type_parameter);
1250        Ok(type_id)
1251    }
1252}