sway_core/abi_generation/
fuel_abi.rs

1use fuel_abi_types::abi::program::{
2    self as program_abi, ConcreteTypeId, ErrorDetails, ErrorPosition, MetadataTypeId,
3    PanickingCall, TypeConcreteDeclaration,
4};
5use sha2::{Digest, Sha256};
6use std::collections::{BTreeMap, HashMap, HashSet};
7use sway_error::{
8    error::CompileError,
9    handler::{ErrorEmitted, Handler},
10};
11use sway_parse::is_valid_identifier_or_path;
12use sway_types::{BaseIdent, Named, Span, Spanned};
13
14use crate::{
15    ast_elements::type_parameter::GenericTypeParameter,
16    language::ty::{TyFunctionDecl, TyProgram, TyProgramKind},
17    transform::Attributes,
18    AbiEncodeSizeHint, Engines, PanicOccurrences, PanickingCallOccurrences, TypeId, TypeInfo,
19};
20
21use super::abi_str::AbiStrContext;
22
23#[derive(Clone, Debug)]
24pub enum AbiNameDiagnosticSpan {
25    Attribute(Span),
26    Type(Span),
27}
28
29impl AbiNameDiagnosticSpan {
30    pub fn span(self) -> Span {
31        match self {
32            Self::Attribute(span) | Self::Type(span) => span,
33        }
34    }
35}
36
37pub struct AbiContext<'a> {
38    pub program: &'a TyProgram,
39    pub panic_occurrences: &'a PanicOccurrences,
40    pub panicking_call_occurrences: &'a PanickingCallOccurrences,
41    pub abi_with_callpaths: bool,
42    pub type_ids_to_full_type_str: HashMap<String, String>,
43    pub unique_names: HashMap<String, AbiNameDiagnosticSpan>,
44}
45
46impl AbiContext<'_> {
47    fn to_str_context(&self) -> AbiStrContext {
48        AbiStrContext {
49            program_name: self.program.namespace.current_package_name().to_string(),
50            abi_with_callpaths: self.abi_with_callpaths,
51            abi_with_fully_specified_types: false,
52            abi_root_type_without_generic_type_parameters: true,
53        }
54    }
55}
56
57pub fn extract_abi_name_inner(span: &Span) -> Option<Span> {
58    let text = &span.src().text;
59    let full_attr = span.as_str();
60
61    // Find the "name" key.
62    let name_key_pos = full_attr.find("name")?;
63    let after_name = &full_attr[name_key_pos..];
64
65    // Find the '=' after "name".
66    let eq_offset_rel = after_name.find('=')?;
67    let after_eq = &after_name[eq_offset_rel + 1..];
68
69    // Find the opening quote of the literal.
70    let first_quote_rel = after_eq.find('"')?;
71    let ident_abs_start = span.start()
72        + name_key_pos
73        + eq_offset_rel
74        + 1        // move past '='
75        + first_quote_rel
76        + 1; // move past the opening '"'
77
78    // Starting at ident_abs_start, locate the closing quote.
79    let rest_after_ident = &text[ident_abs_start..span.end()];
80    let second_quote_rel = rest_after_ident.find('"')?;
81    let ident_abs_end = ident_abs_start + second_quote_rel;
82
83    Span::new(
84        span.src().clone(),
85        ident_abs_start - 1,
86        ident_abs_end + 1,
87        span.source_id().cloned(),
88    )
89}
90
91impl TypeId {
92    fn get_abi_name_and_span_from_type_id(
93        engines: &Engines,
94        type_id: TypeId,
95    ) -> Result<Option<(String, Span)>, ErrorEmitted> {
96        let handler = Handler::default();
97        match *engines.te().get(type_id) {
98            TypeInfo::Enum(decl_id) => {
99                let enum_decl = engines.de().get_enum(&decl_id);
100                match enum_decl.attributes.abi_name() {
101                    Some(abi_name_attr) => {
102                        let name = abi_name_attr
103                            .args
104                            .first()
105                            .unwrap()
106                            .get_string(&handler, abi_name_attr)?;
107                        Ok(Some((name.clone(), abi_name_attr.span.clone())))
108                    }
109                    None => Ok(None),
110                }
111            }
112            TypeInfo::Struct(decl_id) => {
113                let struct_decl = engines.de().get_struct(&decl_id);
114                match struct_decl.attributes.abi_name() {
115                    Some(abi_name_attr) => {
116                        let name = abi_name_attr
117                            .args
118                            .first()
119                            .unwrap()
120                            .get_string(&handler, abi_name_attr)?;
121                        Ok(Some((name.clone(), abi_name_attr.span.clone())))
122                    }
123                    None => Ok(None),
124                }
125            }
126            _ => Ok(None),
127        }
128    }
129
130    fn get_abi_type_field_and_concrete_id(
131        &self,
132        handler: &Handler,
133        ctx: &mut AbiContext,
134        engines: &Engines,
135        resolved_type_id: TypeId,
136    ) -> Result<(String, ConcreteTypeId), ErrorEmitted> {
137        let type_str = self.get_abi_type_str(
138            handler,
139            &AbiStrContext {
140                program_name: ctx.program.namespace.current_package_name().to_string(),
141                abi_with_callpaths: true,
142                abi_with_fully_specified_types: true,
143                abi_root_type_without_generic_type_parameters: false,
144            },
145            engines,
146            resolved_type_id,
147        )?;
148
149        let mut err: Option<ErrorEmitted> = None;
150
151        // Right now ABI renaming is only supported for enum and struct types.
152        let should_check_name = matches!(
153            *engines.te().get(resolved_type_id),
154            TypeInfo::Enum(_) | TypeInfo::Struct(_)
155        );
156
157        if should_check_name {
158            let (has_abi_name_attribute, name, attribute_span) =
159                match Self::get_abi_name_and_span_from_type_id(engines, resolved_type_id)? {
160                    Some(res) => (true, res.0, res.1),
161                    None => (false, String::new(), Span::dummy()),
162                };
163
164            let attribute_name_span =
165                extract_abi_name_inner(&attribute_span).unwrap_or(attribute_span.clone());
166
167            let type_span = match *engines.te().get(resolved_type_id) {
168                TypeInfo::Enum(decl_id) => engines.de().get_enum(&decl_id).name().span(),
169                TypeInfo::Struct(decl_id) => engines.de().get_struct(&decl_id).name().span(),
170                _ => unreachable!(),
171            };
172
173            let insert_span = if has_abi_name_attribute {
174                AbiNameDiagnosticSpan::Attribute(attribute_span.clone())
175            } else {
176                AbiNameDiagnosticSpan::Type(type_span.clone())
177            };
178
179            let prev_span_opt = if ctx.unique_names.contains_key(&type_str) {
180                ctx.unique_names.get(&type_str).cloned()
181            } else {
182                ctx.unique_names.insert(type_str.clone(), insert_span)
183            };
184
185            if has_abi_name_attribute {
186                if name.is_empty()
187                    || !is_valid_identifier_or_path(name.as_str())
188                    || name.starts_with("::")
189                {
190                    err = Some(handler.emit_err(CompileError::ABIInvalidName {
191                        span: attribute_name_span.clone(),
192                        name,
193                    }));
194                }
195
196                if let Some(prev_span) = prev_span_opt {
197                    let is_attribute = matches!(prev_span, AbiNameDiagnosticSpan::Attribute(_));
198                    err = Some(handler.emit_err(CompileError::ABIDuplicateName {
199                        span: attribute_name_span.clone(),
200                        other_span: prev_span.span(),
201                        is_attribute,
202                    }));
203                }
204            }
205        }
206
207        let mut hasher = Sha256::new();
208        hasher.update(type_str.clone());
209        let result = hasher.finalize();
210        let type_id = format!("{result:x}");
211
212        if let Some(old_type_str) = ctx
213            .type_ids_to_full_type_str
214            .insert(type_id.clone(), type_str.clone())
215        {
216            if old_type_str != type_str {
217                err = Some(
218                    handler.emit_err(sway_error::error::CompileError::ABIHashCollision {
219                        span: Span::dummy(),
220                        hash: type_id.clone(),
221                        first_type: old_type_str,
222                        second_type: type_str.clone(),
223                    }),
224                );
225            }
226        }
227
228        match err {
229            Some(err) => Err(err),
230            None => Ok((type_str, ConcreteTypeId(type_id))),
231        }
232    }
233}
234
235fn insert_unique_type(ctx: &mut AbiContext, name: String, span: Span) {
236    let _ = ctx
237        .unique_names
238        .insert(name, AbiNameDiagnosticSpan::Type(span));
239}
240
241fn process_type_name(ctx: &mut AbiContext, engines: &Engines, type_id: TypeId) {
242    match &*engines.te().get(type_id) {
243        TypeInfo::Enum(decl_id) => {
244            let enum_decl = engines.de().get_enum(decl_id);
245            insert_unique_type(
246                ctx,
247                format!("enum {}", enum_decl.name()),
248                enum_decl.name().span(),
249            );
250        }
251        TypeInfo::Struct(decl_id) => {
252            let struct_decl = engines.de().get_struct(decl_id);
253            insert_unique_type(
254                ctx,
255                format!("struct {}", struct_decl.name()),
256                struct_decl.name().span(),
257            );
258        }
259        TypeInfo::Alias { name: _, ty } => process_type_name(ctx, engines, ty.type_id),
260        _ => {}
261    }
262}
263
264fn process_type_names_from_function(
265    ctx: &mut AbiContext,
266    engines: &Engines,
267    function: &TyFunctionDecl,
268) {
269    process_type_name(ctx, engines, function.return_type.type_id);
270
271    for param in &function.parameters {
272        process_type_name(ctx, engines, param.type_argument.type_id);
273    }
274}
275
276pub fn generate_program_abi(
277    handler: &Handler,
278    ctx: &mut AbiContext,
279    engines: &Engines,
280    encoding_version: program_abi::Version,
281    spec_version: program_abi::Version,
282) -> Result<program_abi::ProgramABI, ErrorEmitted> {
283    let decl_engine = engines.de();
284    let metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration> = &mut vec![];
285    let concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration> = &mut vec![];
286
287    match &ctx.program.kind {
288        TyProgramKind::Contract { abi_entries, .. } => {
289            abi_entries.iter().for_each(|x| {
290                let fn_decl = decl_engine.get_function(x);
291                process_type_names_from_function(ctx, engines, &fn_decl);
292            });
293        }
294        TyProgramKind::Script { main_function, .. } => {
295            let main_function = decl_engine.get_function(main_function);
296            process_type_names_from_function(ctx, engines, &main_function);
297        }
298        TyProgramKind::Predicate { main_function, .. } => {
299            let main_function = decl_engine.get_function(main_function);
300            process_type_names_from_function(ctx, engines, &main_function);
301        }
302        TyProgramKind::Library { .. } => {}
303    };
304
305    let mut program_abi = handler.scope(|handler| match &ctx.program.kind {
306        TyProgramKind::Contract { abi_entries, .. } => {
307            let functions = abi_entries
308                .iter()
309                .map(|x| {
310                    let fn_decl = decl_engine.get_function(x);
311                    fn_decl.generate_abi_function(
312                        handler,
313                        ctx,
314                        engines,
315                        metadata_types,
316                        concrete_types,
317                    )
318                })
319                .collect::<Vec<_>>();
320            let logged_types =
321                generate_logged_types(handler, ctx, engines, metadata_types, concrete_types)?;
322            let messages_types =
323                generate_messages_types(handler, ctx, engines, metadata_types, concrete_types)?;
324            let configurables =
325                generate_configurables(handler, ctx, engines, metadata_types, concrete_types)?;
326            let error_codes = generate_error_codes(ctx.panic_occurrences);
327            let panicking_calls = generate_panicking_calls(ctx.panicking_call_occurrences);
328            Ok(program_abi::ProgramABI {
329                program_type: "contract".to_string(),
330                spec_version,
331                encoding_version,
332                metadata_types: metadata_types.to_vec(),
333                concrete_types: concrete_types.to_vec(),
334                functions: functions.into_iter().collect::<Result<Vec<_>, _>>()?,
335                logged_types: Some(logged_types),
336                messages_types: Some(messages_types),
337                configurables: Some(configurables),
338                error_codes: Some(error_codes),
339                panicking_calls: Some(panicking_calls),
340            })
341        }
342        TyProgramKind::Script { main_function, .. } => {
343            let main_function = decl_engine.get_function(main_function);
344            let functions = vec![main_function.generate_abi_function(
345                handler,
346                ctx,
347                engines,
348                metadata_types,
349                concrete_types,
350            )?];
351            let logged_types =
352                generate_logged_types(handler, ctx, engines, metadata_types, concrete_types)?;
353            let messages_types =
354                generate_messages_types(handler, ctx, engines, metadata_types, concrete_types)?;
355            let configurables =
356                generate_configurables(handler, ctx, engines, metadata_types, concrete_types)?;
357            let error_codes = generate_error_codes(ctx.panic_occurrences);
358            let panicking_calls = generate_panicking_calls(ctx.panicking_call_occurrences);
359            Ok(program_abi::ProgramABI {
360                program_type: "script".to_string(),
361                spec_version,
362                encoding_version,
363                metadata_types: metadata_types.to_vec(),
364                concrete_types: concrete_types.to_vec(),
365                functions,
366                logged_types: Some(logged_types),
367                messages_types: Some(messages_types),
368                configurables: Some(configurables),
369                error_codes: Some(error_codes),
370                panicking_calls: Some(panicking_calls),
371            })
372        }
373        TyProgramKind::Predicate { main_function, .. } => {
374            let main_function = decl_engine.get_function(main_function);
375            let functions = vec![main_function.generate_abi_function(
376                handler,
377                ctx,
378                engines,
379                metadata_types,
380                concrete_types,
381            )?];
382            let logged_types =
383                generate_logged_types(handler, ctx, engines, metadata_types, concrete_types)?;
384            let messages_types =
385                generate_messages_types(handler, ctx, engines, metadata_types, concrete_types)?;
386            let configurables =
387                generate_configurables(handler, ctx, engines, metadata_types, concrete_types)?;
388            let error_codes = generate_error_codes(ctx.panic_occurrences);
389            let panicking_calls = generate_panicking_calls(ctx.panicking_call_occurrences);
390            Ok(program_abi::ProgramABI {
391                program_type: "predicate".to_string(),
392                spec_version,
393                encoding_version,
394                metadata_types: metadata_types.to_vec(),
395                concrete_types: concrete_types.to_vec(),
396                functions,
397                logged_types: Some(logged_types),
398                messages_types: Some(messages_types),
399                configurables: Some(configurables),
400                error_codes: Some(error_codes),
401                panicking_calls: Some(panicking_calls),
402            })
403        }
404        TyProgramKind::Library { .. } => {
405            let logged_types =
406                generate_logged_types(handler, ctx, engines, metadata_types, concrete_types)?;
407            let messages_types =
408                generate_messages_types(handler, ctx, engines, metadata_types, concrete_types)?;
409            let error_codes = generate_error_codes(ctx.panic_occurrences);
410            let panicking_calls = generate_panicking_calls(ctx.panicking_call_occurrences);
411            Ok(program_abi::ProgramABI {
412                program_type: "library".to_string(),
413                spec_version,
414                encoding_version,
415                metadata_types: metadata_types.to_vec(),
416                concrete_types: concrete_types.to_vec(),
417                functions: vec![],
418                logged_types: Some(logged_types),
419                messages_types: Some(messages_types),
420                configurables: None,
421                error_codes: Some(error_codes),
422                panicking_calls: Some(panicking_calls),
423            })
424        }
425    })?;
426
427    standardize_json_abi_types(&mut program_abi);
428
429    Ok(program_abi)
430}
431
432/// Standardize the JSON ABI data structure by eliminating duplicate types. This is an iterative
433/// process because every time two types are merged, new opportunities for more merging arise.
434fn standardize_json_abi_types(json_abi_program: &mut program_abi::ProgramABI) {
435    // Dedup TypeMetadataDeclaration
436    loop {
437        // If type with id_1 is a duplicate of type with id_2, then keep track of the mapping
438        // between id_1 and id_2 in the HashMap below.
439        let mut old_to_new_id: HashMap<MetadataTypeId, program_abi::TypeId> = HashMap::new();
440
441        // A vector containing unique `program_abi::TypeMetadataDeclaration`s.
442        //
443        // Two `program_abi::TypeMetadataDeclaration` are deemed the same if the have the same
444        // `type_field`, `components`, and `type_parameters` (even if their `type_id`s are
445        // different).
446        let mut deduped_types: Vec<program_abi::TypeMetadataDeclaration> = Vec::new();
447
448        // Insert values in `deduped_types` if they haven't been inserted before. Otherwise, create
449        // an appropriate mapping between type IDs in the HashMap `old_to_new_id`.
450        for decl in &json_abi_program.metadata_types {
451            // First replace metadata_type_id with concrete_type_id when possible
452            if let Some(ty) = json_abi_program.concrete_types.iter().find(|d| {
453                d.type_field == decl.type_field
454                    && decl.components.is_none()
455                    && decl.type_parameters.is_none()
456            }) {
457                old_to_new_id.insert(
458                    decl.metadata_type_id.clone(),
459                    program_abi::TypeId::Concrete(ty.concrete_type_id.clone()),
460                );
461            } else {
462                // Second replace metadata_type_id with metadata_type_id when possible
463                if let Some(ty) = deduped_types.iter().find(|d| {
464                    d.type_field == decl.type_field
465                        && d.components == decl.components
466                        && d.type_parameters == decl.type_parameters
467                }) {
468                    old_to_new_id.insert(
469                        decl.metadata_type_id.clone(),
470                        program_abi::TypeId::Metadata(ty.metadata_type_id.clone()),
471                    );
472                } else {
473                    deduped_types.push(decl.clone());
474                }
475            }
476        }
477
478        // Nothing to do if the hash map is empty as there are not merge opportunities. We can now
479        // exit the loop.
480        if old_to_new_id.is_empty() {
481            break;
482        }
483
484        json_abi_program.metadata_types = deduped_types;
485
486        update_all_types(json_abi_program, &old_to_new_id);
487    }
488
489    // Dedup TypeConcreteDeclaration
490    let mut concrete_declarations_map: HashMap<ConcreteTypeId, TypeConcreteDeclaration> =
491        HashMap::new();
492    for decl in &json_abi_program.concrete_types {
493        concrete_declarations_map.insert(decl.concrete_type_id.clone(), decl.clone());
494    }
495    json_abi_program.concrete_types = concrete_declarations_map.values().cloned().collect();
496
497    // Sort the `program_abi::TypeMetadataDeclaration`s
498    json_abi_program
499        .metadata_types
500        .sort_by(|t1, t2| t1.type_field.cmp(&t2.type_field));
501
502    // Sort the `program_abi::TypeConcreteDeclaration`s
503    json_abi_program
504        .concrete_types
505        .sort_by(|t1, t2| t1.type_field.cmp(&t2.type_field));
506
507    // Standardize IDs (i.e. change them to 0,1,2,... according to the alphabetical order above
508    let mut old_to_new_id: HashMap<MetadataTypeId, program_abi::TypeId> = HashMap::new();
509    for (ix, decl) in json_abi_program.metadata_types.iter_mut().enumerate() {
510        old_to_new_id.insert(
511            decl.metadata_type_id.clone(),
512            program_abi::TypeId::Metadata(MetadataTypeId(ix)),
513        );
514        decl.metadata_type_id = MetadataTypeId(ix);
515    }
516
517    update_all_types(json_abi_program, &old_to_new_id);
518}
519
520/// Recursively updates the type IDs used in a program_abi::ProgramABI
521fn update_all_types(
522    json_abi_program: &mut program_abi::ProgramABI,
523    old_to_new_id: &HashMap<MetadataTypeId, program_abi::TypeId>,
524) {
525    // Update all `program_abi::TypeMetadataDeclaration`
526    for decl in &mut json_abi_program.metadata_types {
527        update_json_type_metadata_declaration(decl, old_to_new_id);
528    }
529
530    // Update all `program_abi::TypeConcreteDeclaration`
531    for decl in &mut json_abi_program.concrete_types {
532        update_json_type_concrete_declaration(decl, old_to_new_id);
533    }
534}
535
536/// Recursively updates the type IDs used in a `program_abi::TypeApplication` given a HashMap from
537/// old to new IDs
538fn update_json_type_application(
539    type_application: &mut program_abi::TypeApplication,
540    old_to_new_id: &HashMap<MetadataTypeId, program_abi::TypeId>,
541) {
542    if let fuel_abi_types::abi::program::TypeId::Metadata(metadata_type_id) =
543        &type_application.type_id
544    {
545        if let Some(new_id) = old_to_new_id.get(metadata_type_id) {
546            type_application.type_id = new_id.clone();
547        }
548    }
549
550    if let Some(args) = &mut type_application.type_arguments {
551        for arg in args.iter_mut() {
552            update_json_type_application(arg, old_to_new_id);
553        }
554    }
555}
556
557/// Recursively updates the metadata type IDs used in a `program_abi::TypeMetadataDeclaration` given a HashMap from
558/// old to new IDs
559fn update_json_type_metadata_declaration(
560    type_declaration: &mut program_abi::TypeMetadataDeclaration,
561    old_to_new_id: &HashMap<MetadataTypeId, program_abi::TypeId>,
562) {
563    if let Some(params) = &mut type_declaration.type_parameters {
564        for param in params.iter_mut() {
565            if let Some(fuel_abi_types::abi::program::TypeId::Metadata(new_id)) =
566                old_to_new_id.get(param)
567            {
568                *param = new_id.clone();
569            }
570        }
571    }
572
573    if let Some(components) = &mut type_declaration.components {
574        for component in components.iter_mut() {
575            update_json_type_application(component, old_to_new_id);
576        }
577    }
578}
579
580/// Updates the metadata type IDs used in a `program_abi::TypeConcreteDeclaration` given a HashMap from
581/// old to new IDs
582fn update_json_type_concrete_declaration(
583    type_declaration: &mut program_abi::TypeConcreteDeclaration,
584    old_to_new_id: &HashMap<MetadataTypeId, program_abi::TypeId>,
585) {
586    if let Some(metadata_type_id) = &mut type_declaration.metadata_type_id {
587        if let Some(fuel_abi_types::abi::program::TypeId::Metadata(new_id)) =
588            old_to_new_id.get(metadata_type_id)
589        {
590            *metadata_type_id = new_id.clone();
591        }
592    }
593}
594
595fn generate_concrete_type_declaration(
596    handler: &Handler,
597    ctx: &mut AbiContext,
598    engines: &Engines,
599    metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
600    concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
601    type_id: TypeId,
602    resolved_type_id: TypeId,
603) -> Result<ConcreteTypeId, ErrorEmitted> {
604    let mut new_metadata_types_to_add = Vec::<program_abi::TypeMetadataDeclaration>::new();
605    let type_metadata_decl = program_abi::TypeMetadataDeclaration {
606        metadata_type_id: MetadataTypeId(type_id.index()),
607        type_field: type_id.get_abi_type_str(
608            handler,
609            &ctx.to_str_context(),
610            engines,
611            resolved_type_id,
612        )?,
613        components: type_id.get_abi_type_components(
614            handler,
615            ctx,
616            engines,
617            metadata_types,
618            concrete_types,
619            resolved_type_id,
620            &mut new_metadata_types_to_add,
621        )?,
622        type_parameters: type_id.get_abi_type_parameters(
623            handler,
624            ctx,
625            engines,
626            metadata_types,
627            concrete_types,
628            resolved_type_id,
629            &mut new_metadata_types_to_add,
630        )?,
631    };
632
633    let metadata_type_id = if type_metadata_decl.type_parameters.is_some()
634        || type_metadata_decl.components.is_some()
635    {
636        Some(type_metadata_decl.metadata_type_id.clone())
637    } else {
638        None
639    };
640    let type_arguments = handler.scope(|handler| {
641        let type_arguments = if type_metadata_decl.type_parameters.is_some() {
642            type_id.get_abi_type_arguments_as_concrete_type_ids(
643                handler,
644                ctx,
645                engines,
646                metadata_types,
647                concrete_types,
648                resolved_type_id,
649            )?
650        } else {
651            None
652        };
653        Ok(type_arguments)
654    })?;
655
656    metadata_types.push(type_metadata_decl);
657    metadata_types.extend(new_metadata_types_to_add);
658
659    let (type_field, concrete_type_id) =
660        type_id.get_abi_type_field_and_concrete_id(handler, ctx, engines, resolved_type_id)?;
661    let concrete_type_decl = TypeConcreteDeclaration {
662        type_field,
663        concrete_type_id: concrete_type_id.clone(),
664        metadata_type_id,
665        type_arguments,
666        alias_of: None,
667    };
668
669    concrete_types.push(concrete_type_decl);
670
671    Ok(concrete_type_id)
672}
673
674#[allow(clippy::too_many_arguments)]
675fn generate_type_metadata_declaration(
676    handler: &Handler,
677    ctx: &mut AbiContext,
678    engines: &Engines,
679    metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
680    concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
681    type_id: TypeId,
682    resolved_type_id: TypeId,
683    metadata_types_to_add: &mut Vec<program_abi::TypeMetadataDeclaration>,
684) -> Result<(), ErrorEmitted> {
685    let mut new_metadata_types_to_add = Vec::<program_abi::TypeMetadataDeclaration>::new();
686    let components = type_id.get_abi_type_components(
687        handler,
688        ctx,
689        engines,
690        metadata_types,
691        concrete_types,
692        resolved_type_id,
693        &mut new_metadata_types_to_add,
694    )?;
695    let type_parameters = type_id.get_abi_type_parameters(
696        handler,
697        ctx,
698        engines,
699        metadata_types,
700        concrete_types,
701        resolved_type_id,
702        &mut new_metadata_types_to_add,
703    )?;
704    let type_metadata_decl = program_abi::TypeMetadataDeclaration {
705        metadata_type_id: MetadataTypeId(type_id.index()),
706        type_field: type_id.get_abi_type_str(
707            handler,
708            &ctx.to_str_context(),
709            engines,
710            resolved_type_id,
711        )?,
712        components,
713        type_parameters,
714    };
715
716    metadata_types_to_add.push(type_metadata_decl.clone());
717    metadata_types_to_add.extend(new_metadata_types_to_add);
718
719    Ok(())
720}
721
722fn generate_logged_types(
723    handler: &Handler,
724    ctx: &mut AbiContext,
725    engines: &Engines,
726    metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
727    concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
728) -> Result<Vec<program_abi::LoggedType>, ErrorEmitted> {
729    // Generate the JSON data for the logged types
730    let mut log_ids: HashSet<u64> = HashSet::default();
731    Ok(ctx
732        .program
733        .logged_types
734        .iter()
735        .map(|(log_id, type_id)| {
736            let log_id = log_id.hash_id;
737            if log_ids.contains(&log_id) {
738                Ok(None)
739            } else {
740                log_ids.insert(log_id);
741                Ok(Some(program_abi::LoggedType {
742                    log_id: log_id.to_string(),
743                    concrete_type_id: generate_concrete_type_declaration(
744                        handler,
745                        ctx,
746                        engines,
747                        metadata_types,
748                        concrete_types,
749                        *type_id,
750                        *type_id,
751                    )?,
752                }))
753            }
754        })
755        .collect::<Result<Vec<_>, _>>()?
756        .into_iter()
757        .flatten()
758        .collect())
759}
760
761fn generate_messages_types(
762    handler: &Handler,
763    ctx: &mut AbiContext,
764    engines: &Engines,
765    metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
766    concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
767) -> Result<Vec<program_abi::MessageType>, ErrorEmitted> {
768    // Generate the JSON data for the messages types
769    ctx.program
770        .messages_types
771        .iter()
772        .map(|(message_id, type_id)| {
773            Ok(program_abi::MessageType {
774                message_id: (**message_id as u64).to_string(),
775                concrete_type_id: generate_concrete_type_declaration(
776                    handler,
777                    ctx,
778                    engines,
779                    metadata_types,
780                    concrete_types,
781                    *type_id,
782                    *type_id,
783                )?,
784            })
785        })
786        .collect::<Result<Vec<_>, _>>()
787}
788
789fn generate_configurables(
790    handler: &Handler,
791    ctx: &mut AbiContext,
792    engines: &Engines,
793    metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
794    concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
795) -> Result<Vec<program_abi::Configurable>, ErrorEmitted> {
796    // Generate the JSON data for the configurables types
797    ctx.program
798        .configurables
799        .iter()
800        .map(|decl| {
801            Ok(program_abi::Configurable {
802                name: decl.call_path.suffix.to_string(),
803                concrete_type_id: generate_concrete_type_declaration(
804                    handler,
805                    ctx,
806                    engines,
807                    metadata_types,
808                    concrete_types,
809                    decl.type_ascription.type_id,
810                    decl.type_ascription.type_id,
811                )?,
812                offset: 0,
813                indirect: false,
814            })
815        })
816        .collect::<Result<Vec<_>, _>>()
817}
818
819fn generate_error_codes(panic_occurrences: &PanicOccurrences) -> BTreeMap<u64, ErrorDetails> {
820    panic_occurrences
821        .iter()
822        .map(|(panic_occurrence, &panic_error_code)| {
823            (
824                panic_error_code,
825                ErrorDetails {
826                    pos: ErrorPosition {
827                        function: panic_occurrence.function.clone(),
828                        pkg: panic_occurrence.loc.pkg.clone(),
829                        file: panic_occurrence.loc.file.clone(),
830                        line: panic_occurrence.loc.loc.line as u64,
831                        column: panic_occurrence.loc.loc.col as u64,
832                    },
833                    log_id: panic_occurrence
834                        .log_id
835                        .map(|log_id| log_id.hash_id.to_string()),
836                    msg: panic_occurrence.msg.clone(),
837                },
838            )
839        })
840        .collect()
841}
842
843fn generate_panicking_calls(
844    panicking_call_occurrences: &PanickingCallOccurrences,
845) -> BTreeMap<u64, PanickingCall> {
846    panicking_call_occurrences
847        .iter()
848        .map(|(panicking_call_occurrence, panicking_call_id)| {
849            (
850                *panicking_call_id,
851                PanickingCall {
852                    pos: ErrorPosition {
853                        function: panicking_call_occurrence.caller_function.clone(),
854                        pkg: panicking_call_occurrence.loc.pkg.clone(),
855                        file: panicking_call_occurrence.loc.file.clone(),
856                        line: panicking_call_occurrence.loc.loc.line as u64,
857                        column: panicking_call_occurrence.loc.loc.col as u64,
858                    },
859                    function: panicking_call_occurrence.function.clone(),
860                },
861            )
862        })
863        .collect()
864}
865
866impl TypeId {
867    /// Return the type parameters of a given (potentially generic) type while considering what it
868    /// actually resolves to. These parameters are essentially of type of `usize` which are
869    /// basically the IDs of some set of `program_abi::TypeMetadataDeclaration`s. The method below also
870    /// updates the provide list of `program_abi::TypeMetadataDeclaration`s  to add the newly discovered
871    /// types.
872    #[allow(clippy::too_many_arguments)]
873    pub(self) fn get_abi_type_parameters(
874        &self,
875        handler: &Handler,
876        ctx: &mut AbiContext,
877        engines: &Engines,
878        metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
879        concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
880        resolved_type_id: TypeId,
881        metadata_types_to_add: &mut Vec<program_abi::TypeMetadataDeclaration>,
882    ) -> Result<Option<Vec<MetadataTypeId>>, ErrorEmitted> {
883        match self.is_generic_parameter(engines, resolved_type_id) {
884            true => Ok(None),
885            false => resolved_type_id
886                .get_type_parameters(engines)
887                .map(|v| {
888                    v.iter()
889                        .map(|p| {
890                            let p = p
891                                .as_type_parameter()
892                                .expect("only works with type parameters");
893                            p.get_abi_type_parameter(
894                                handler,
895                                ctx,
896                                engines,
897                                metadata_types,
898                                concrete_types,
899                                metadata_types_to_add,
900                            )
901                        })
902                        .collect::<Result<Vec<_>, _>>()
903                })
904                .map_or(Ok(None), |v| v.map(Some)),
905        }
906    }
907
908    /// Updates the running struct offset and returns the offset for the current field if it is indexed.
909    fn update_indexed_field_offset(
910        handler: &Handler,
911        running_offset: &mut usize,
912        field_name: BaseIdent,
913        field_size: usize,
914        is_indexed: bool,
915    ) -> Result<Option<u16>, ErrorEmitted> {
916        if !is_indexed {
917            return Ok(None);
918        }
919
920        let current_offset = *running_offset;
921        *running_offset = match current_offset.checked_add(field_size) {
922            Some(offset) => offset,
923            None => {
924                return Err(handler.emit_err(CompileError::IndexedFieldOffsetTooLarge {
925                    field_name: sway_types::IdentUnique::from(field_name.clone()),
926                }));
927            }
928        };
929
930        if *running_offset > (u16::MAX as usize + 1) {
931            return Err(handler.emit_err(CompileError::IndexedFieldOffsetTooLarge {
932                field_name: sway_types::IdentUnique::from(field_name.clone()),
933            }));
934        }
935
936        if current_offset > u16::MAX as usize {
937            return Err(handler.emit_err(CompileError::IndexedFieldOffsetTooLarge {
938                field_name: sway_types::IdentUnique::from(field_name),
939            }));
940        }
941
942        Ok(Some(current_offset as u16))
943    }
944
945    /// Return the components of a given (potentially generic) type while considering what it
946    /// actually resolves to. These components are essentially of type of
947    /// `program_abi::TypeApplication`.  The method below also updates the provided list of
948    /// `program_abi::TypeMetadataDeclaration`s  to add the newly discovered types.
949    #[allow(clippy::too_many_arguments)]
950    pub(self) fn get_abi_type_components(
951        &self,
952        handler: &Handler,
953        ctx: &mut AbiContext,
954        engines: &Engines,
955        metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
956        concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
957        resolved_type_id: TypeId,
958        metadata_types_to_add: &mut Vec<program_abi::TypeMetadataDeclaration>,
959    ) -> Result<Option<Vec<program_abi::TypeApplication>>, ErrorEmitted> {
960        let type_engine = engines.te();
961        let decl_engine = engines.de();
962        Ok(match &*type_engine.get(*self) {
963            TypeInfo::Enum(decl_ref) => {
964                let decl = decl_engine.get_enum(decl_ref);
965
966                let mut new_metadata_types_to_add =
967                    Vec::<program_abi::TypeMetadataDeclaration>::new();
968                for variant in decl.variants.iter() {
969                    generate_type_metadata_declaration(
970                        handler,
971                        ctx,
972                        engines,
973                        metadata_types,
974                        concrete_types,
975                        variant.type_argument.initial_type_id,
976                        variant.type_argument.type_id,
977                        &mut new_metadata_types_to_add,
978                    )?;
979                }
980
981                // Generate the JSON data for the enum. This is basically a list of
982                // `program_abi::TypeApplication`s
983                let components = decl
984                    .variants
985                    .iter()
986                    .map(|variant| {
987                        Ok(program_abi::TypeApplication {
988                            name: variant.name.to_string(),
989                            type_id: program_abi::TypeId::Metadata(MetadataTypeId(
990                                variant.type_argument.initial_type_id.index(),
991                            )),
992                            error_message: variant.attributes.error_message().cloned(),
993                            type_arguments: variant
994                                .type_argument
995                                .initial_type_id
996                                .get_abi_type_arguments(
997                                    handler,
998                                    ctx,
999                                    engines,
1000                                    metadata_types,
1001                                    concrete_types,
1002                                    variant.type_argument.type_id,
1003                                    &mut new_metadata_types_to_add,
1004                                )?,
1005                            offset: None,
1006                        })
1007                    })
1008                    .collect::<Result<Vec<_>, _>>()?;
1009
1010                if components.is_empty() {
1011                    None
1012                } else {
1013                    metadata_types_to_add.extend(new_metadata_types_to_add);
1014                    Some(components)
1015                }
1016            }
1017            TypeInfo::Struct(decl_ref) => {
1018                let decl = decl_engine.get_struct(decl_ref);
1019
1020                let mut new_metadata_types_to_add =
1021                    Vec::<program_abi::TypeMetadataDeclaration>::new();
1022                for field in decl.fields.iter() {
1023                    generate_type_metadata_declaration(
1024                        handler,
1025                        ctx,
1026                        engines,
1027                        metadata_types,
1028                        concrete_types,
1029                        field.type_argument.initial_type_id,
1030                        field.type_argument.type_id,
1031                        &mut new_metadata_types_to_add,
1032                    )?;
1033                }
1034
1035                // Generate the JSON data for the struct. This is basically a list of
1036                // `program_abi::TypeApplication`s
1037                let mut running_offset = 0usize;
1038                let components = decl
1039                    .fields
1040                    .iter()
1041                    .map(|field| {
1042                        let hint = engines
1043                            .te()
1044                            .get(field.type_argument.type_id)
1045                            .abi_encode_size_hint(engines);
1046                        let is_indexed = field.attributes.indexed().is_some();
1047
1048                        let field_size = if is_indexed {
1049                            match hint {
1050                                AbiEncodeSizeHint::Exact(sz) => sz,
1051                                _ => unreachable!("expected exact size hint for indexed field"),
1052                            }
1053                        } else {
1054                            0
1055                        };
1056
1057                        let offset = TypeId::update_indexed_field_offset(
1058                            handler,
1059                            &mut running_offset,
1060                            field.name.clone(),
1061                            field_size,
1062                            is_indexed,
1063                        )?;
1064
1065                        Ok(program_abi::TypeApplication {
1066                            name: field.name.to_string(),
1067                            type_id: program_abi::TypeId::Metadata(MetadataTypeId(
1068                                field.type_argument.initial_type_id.index(),
1069                            )),
1070                            error_message: None,
1071                            type_arguments: field
1072                                .type_argument
1073                                .initial_type_id
1074                                .get_abi_type_arguments(
1075                                    handler,
1076                                    ctx,
1077                                    engines,
1078                                    metadata_types,
1079                                    concrete_types,
1080                                    field.type_argument.type_id,
1081                                    &mut new_metadata_types_to_add,
1082                                )?,
1083                            offset,
1084                        })
1085                    })
1086                    .collect::<Result<Vec<_>, _>>()?;
1087
1088                if components.is_empty() {
1089                    None
1090                } else {
1091                    metadata_types_to_add.extend(new_metadata_types_to_add);
1092                    Some(components)
1093                }
1094            }
1095            TypeInfo::Array(..) => {
1096                if let TypeInfo::Array(elem_ty, _) = &*type_engine.get(resolved_type_id) {
1097                    generate_type_metadata_declaration(
1098                        handler,
1099                        ctx,
1100                        engines,
1101                        metadata_types,
1102                        concrete_types,
1103                        elem_ty.initial_type_id,
1104                        elem_ty.type_id,
1105                        metadata_types_to_add,
1106                    )?;
1107
1108                    // Generate the JSON data for the array. This is basically a single
1109                    // `program_abi::TypeApplication` for the array element type
1110                    Some(vec![program_abi::TypeApplication {
1111                        name: "__array_element".to_string(),
1112                        type_id: program_abi::TypeId::Metadata(MetadataTypeId(
1113                            elem_ty.initial_type_id.index(),
1114                        )),
1115                        error_message: None,
1116                        type_arguments: elem_ty.initial_type_id.get_abi_type_arguments(
1117                            handler,
1118                            ctx,
1119                            engines,
1120                            metadata_types,
1121                            concrete_types,
1122                            elem_ty.type_id,
1123                            metadata_types_to_add,
1124                        )?,
1125                        offset: None,
1126                    }])
1127                } else {
1128                    unreachable!();
1129                }
1130            }
1131            TypeInfo::Slice(..) => {
1132                if let TypeInfo::Slice(elem_ty) = &*type_engine.get(resolved_type_id) {
1133                    generate_type_metadata_declaration(
1134                        handler,
1135                        ctx,
1136                        engines,
1137                        metadata_types,
1138                        concrete_types,
1139                        elem_ty.initial_type_id,
1140                        elem_ty.type_id,
1141                        metadata_types_to_add,
1142                    )?;
1143
1144                    // Generate the JSON data for the array. This is basically a single
1145                    // `program_abi::TypeApplication` for the array element type
1146                    Some(vec![program_abi::TypeApplication {
1147                        name: "__slice_element".to_string(),
1148                        type_id: program_abi::TypeId::Metadata(MetadataTypeId(
1149                            elem_ty.initial_type_id.index(),
1150                        )),
1151                        error_message: None,
1152                        type_arguments: elem_ty.initial_type_id.get_abi_type_arguments(
1153                            handler,
1154                            ctx,
1155                            engines,
1156                            metadata_types,
1157                            concrete_types,
1158                            elem_ty.type_id,
1159                            metadata_types_to_add,
1160                        )?,
1161                        offset: None,
1162                    }])
1163                } else {
1164                    unreachable!();
1165                }
1166            }
1167            TypeInfo::Tuple(_) => {
1168                if let TypeInfo::Tuple(fields) = &*type_engine.get(resolved_type_id) {
1169                    let mut new_metadata_types_to_add =
1170                        Vec::<program_abi::TypeMetadataDeclaration>::new();
1171                    for x in fields.iter() {
1172                        generate_type_metadata_declaration(
1173                            handler,
1174                            ctx,
1175                            engines,
1176                            metadata_types,
1177                            concrete_types,
1178                            x.initial_type_id,
1179                            x.type_id,
1180                            &mut new_metadata_types_to_add,
1181                        )?;
1182                    }
1183
1184                    // Generate the JSON data for the tuple. This is basically a list of
1185                    // `program_abi::TypeApplication`s
1186                    let components = fields
1187                        .iter()
1188                        .map(|x| {
1189                            Ok(program_abi::TypeApplication {
1190                                name: "__tuple_element".to_string(),
1191                                type_id: program_abi::TypeId::Metadata(MetadataTypeId(
1192                                    x.initial_type_id.index(),
1193                                )),
1194                                error_message: None,
1195                                type_arguments: x.initial_type_id.get_abi_type_arguments(
1196                                    handler,
1197                                    ctx,
1198                                    engines,
1199                                    metadata_types,
1200                                    concrete_types,
1201                                    x.type_id,
1202                                    metadata_types_to_add,
1203                                )?,
1204                                offset: None,
1205                            })
1206                        })
1207                        .collect::<Result<Vec<_>, _>>()?;
1208                    if components.is_empty() {
1209                        None
1210                    } else {
1211                        metadata_types_to_add.extend(new_metadata_types_to_add);
1212                        Some(components)
1213                    }
1214                } else {
1215                    unreachable!()
1216                }
1217            }
1218            TypeInfo::Custom { type_arguments, .. } => {
1219                if !self.is_generic_parameter(engines, resolved_type_id) {
1220                    for (v, p) in type_arguments.clone().unwrap_or_default().iter().zip(
1221                        resolved_type_id
1222                            .get_type_parameters(engines)
1223                            .unwrap_or_default()
1224                            .iter(),
1225                    ) {
1226                        let p = p
1227                            .as_type_parameter()
1228                            .expect("only works with type parameters");
1229                        generate_type_metadata_declaration(
1230                            handler,
1231                            ctx,
1232                            engines,
1233                            metadata_types,
1234                            concrete_types,
1235                            v.initial_type_id(),
1236                            p.type_id,
1237                            metadata_types_to_add,
1238                        )?;
1239                    }
1240                    resolved_type_id.get_abi_type_components(
1241                        handler,
1242                        ctx,
1243                        engines,
1244                        metadata_types,
1245                        concrete_types,
1246                        resolved_type_id,
1247                        metadata_types_to_add,
1248                    )?
1249                } else {
1250                    None
1251                }
1252            }
1253            TypeInfo::Alias { .. } => {
1254                if let TypeInfo::Alias { ty, .. } = &*type_engine.get(resolved_type_id) {
1255                    ty.initial_type_id.get_abi_type_components(
1256                        handler,
1257                        ctx,
1258                        engines,
1259                        metadata_types,
1260                        concrete_types,
1261                        ty.type_id,
1262                        metadata_types_to_add,
1263                    )?
1264                } else {
1265                    None
1266                }
1267            }
1268            TypeInfo::UnknownGeneric { .. } => {
1269                // avoid infinite recursion
1270                if *self == resolved_type_id {
1271                    None
1272                } else {
1273                    resolved_type_id.get_abi_type_components(
1274                        handler,
1275                        ctx,
1276                        engines,
1277                        metadata_types,
1278                        concrete_types,
1279                        resolved_type_id,
1280                        metadata_types_to_add,
1281                    )?
1282                }
1283            }
1284            _ => None,
1285        })
1286    }
1287
1288    /// Return the type arguments of a given (potentially generic) type while considering what it
1289    /// actually resolves to. These arguments are essentially of type of
1290    /// `program_abi::TypeApplication`. The method below also updates the provided list of
1291    /// `program_abi::TypeMetadataDeclaration`s  to add the newly discovered types.
1292    #[allow(clippy::too_many_arguments)]
1293    pub(self) fn get_abi_type_arguments(
1294        &self,
1295        handler: &Handler,
1296        ctx: &mut AbiContext,
1297        engines: &Engines,
1298        metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
1299        concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
1300        resolved_type_id: TypeId,
1301        metadata_types_to_add: &mut Vec<program_abi::TypeMetadataDeclaration>,
1302    ) -> Result<Option<Vec<program_abi::TypeApplication>>, ErrorEmitted> {
1303        let type_engine = engines.te();
1304        let decl_engine = engines.de();
1305        let resolved_params = resolved_type_id.get_type_parameters(engines);
1306        handler.scope(|handler| {
1307            Ok(match &*type_engine.get(*self) {
1308                TypeInfo::Custom {
1309                    type_arguments: Some(type_arguments),
1310                    ..
1311                } => (!type_arguments.is_empty()).then_some({
1312                    let resolved_params = resolved_params.unwrap_or_default();
1313                    for (v, p) in type_arguments.iter().zip(resolved_params.iter()) {
1314                        let p = p
1315                            .as_type_parameter()
1316                            .expect("only works with type parameters");
1317                        let _ = generate_type_metadata_declaration(
1318                            handler,
1319                            ctx,
1320                            engines,
1321                            metadata_types,
1322                            concrete_types,
1323                            v.type_id(),
1324                            p.type_id,
1325                            metadata_types_to_add,
1326                        );
1327                    }
1328
1329                    type_arguments
1330                        .iter()
1331                        .zip(resolved_params.iter())
1332                        .map(|(arg, p)| {
1333                            let p = p
1334                                .as_type_parameter()
1335                                .expect("only works with type parameters");
1336                            Ok(program_abi::TypeApplication {
1337                                name: "".to_string(),
1338                                type_id: program_abi::TypeId::Metadata(MetadataTypeId(
1339                                    arg.initial_type_id().index(),
1340                                )),
1341                                error_message: None,
1342                                type_arguments: arg.initial_type_id().get_abi_type_arguments(
1343                                    handler,
1344                                    ctx,
1345                                    engines,
1346                                    metadata_types,
1347                                    concrete_types,
1348                                    p.type_id,
1349                                    metadata_types_to_add,
1350                                )?,
1351                                offset: None,
1352                            })
1353                        })
1354                        .collect::<Result<Vec<_>, _>>()?
1355                }),
1356                TypeInfo::Enum(decl_ref) => {
1357                    let decl = decl_engine.get_enum(decl_ref);
1358
1359                    let mut new_metadata_types_to_add =
1360                        Vec::<program_abi::TypeMetadataDeclaration>::new();
1361                    for p in decl.generic_parameters.iter() {
1362                        let p = p
1363                            .as_type_parameter()
1364                            .expect("only works with type parameters");
1365                        generate_type_metadata_declaration(
1366                            handler,
1367                            ctx,
1368                            engines,
1369                            metadata_types,
1370                            concrete_types,
1371                            p.type_id,
1372                            p.type_id,
1373                            &mut new_metadata_types_to_add,
1374                        )?;
1375                    }
1376
1377                    let type_arguments = decl
1378                        .generic_parameters
1379                        .iter()
1380                        .map(|p| {
1381                            let p = p
1382                                .as_type_parameter()
1383                                .expect("only works with type parameters");
1384                            Ok(program_abi::TypeApplication {
1385                                name: "".to_string(),
1386                                type_id: program_abi::TypeId::Metadata(MetadataTypeId(
1387                                    p.type_id.index(),
1388                                )),
1389                                error_message: None,
1390                                type_arguments: p.type_id.get_abi_type_arguments(
1391                                    handler,
1392                                    ctx,
1393                                    engines,
1394                                    metadata_types,
1395                                    concrete_types,
1396                                    p.type_id,
1397                                    &mut new_metadata_types_to_add,
1398                                )?,
1399                                offset: None,
1400                            })
1401                        })
1402                        .collect::<Result<Vec<_>, _>>()?;
1403
1404                    if type_arguments.is_empty() {
1405                        None
1406                    } else {
1407                        metadata_types_to_add.extend(new_metadata_types_to_add);
1408                        Some(type_arguments)
1409                    }
1410                }
1411
1412                TypeInfo::Struct(decl_ref) => {
1413                    let decl = decl_engine.get_struct(decl_ref);
1414
1415                    let mut new_metadata_types_to_add =
1416                        Vec::<program_abi::TypeMetadataDeclaration>::new();
1417                    for p in decl.generic_parameters.iter() {
1418                        let p = p
1419                            .as_type_parameter()
1420                            .expect("only works with type parameters");
1421                        generate_type_metadata_declaration(
1422                            handler,
1423                            ctx,
1424                            engines,
1425                            metadata_types,
1426                            concrete_types,
1427                            p.type_id,
1428                            p.type_id,
1429                            &mut new_metadata_types_to_add,
1430                        )?;
1431                    }
1432
1433                    let type_arguments = decl
1434                        .generic_parameters
1435                        .iter()
1436                        .map(|p| {
1437                            let p = p
1438                                .as_type_parameter()
1439                                .expect("only works with type parameters");
1440                            Ok(program_abi::TypeApplication {
1441                                name: "".to_string(),
1442                                type_id: program_abi::TypeId::Metadata(MetadataTypeId(
1443                                    p.type_id.index(),
1444                                )),
1445                                error_message: None,
1446                                type_arguments: p.type_id.get_abi_type_arguments(
1447                                    handler,
1448                                    ctx,
1449                                    engines,
1450                                    metadata_types,
1451                                    concrete_types,
1452                                    p.type_id,
1453                                    &mut new_metadata_types_to_add,
1454                                )?,
1455                                offset: None,
1456                            })
1457                        })
1458                        .collect::<Result<Vec<_>, _>>()?;
1459
1460                    if type_arguments.is_empty() {
1461                        None
1462                    } else {
1463                        metadata_types_to_add.extend(new_metadata_types_to_add);
1464                        Some(type_arguments)
1465                    }
1466                }
1467                _ => None,
1468            })
1469        })
1470    }
1471
1472    /// Return the type arguments of a given (potentially generic) type while considering what it
1473    /// actually resolves to. These arguments are essentially of type of
1474    /// `program_abi::TypeApplication`. The method below also updates the provided list of
1475    /// `program_abi::TypeMetadataDeclaration`s  to add the newly discovered types.
1476    pub(self) fn get_abi_type_arguments_as_concrete_type_ids(
1477        &self,
1478        handler: &Handler,
1479        ctx: &mut AbiContext,
1480        engines: &Engines,
1481        metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
1482        concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
1483        resolved_type_id: TypeId,
1484    ) -> Result<Option<Vec<program_abi::ConcreteTypeId>>, ErrorEmitted> {
1485        let type_engine = engines.te();
1486        let decl_engine = engines.de();
1487        let resolved_params = resolved_type_id.get_type_parameters(engines);
1488        Ok(match &*type_engine.get(*self) {
1489            TypeInfo::Custom {
1490                type_arguments: Some(type_arguments),
1491                ..
1492            } => (!type_arguments.is_empty()).then_some({
1493                let resolved_params = resolved_params.unwrap_or_default();
1494                type_arguments
1495                    .iter()
1496                    .zip(resolved_params.iter())
1497                    .map(|(arg, p)| {
1498                        let p = p
1499                            .as_type_parameter()
1500                            .expect("only works with type parameters");
1501                        generate_concrete_type_declaration(
1502                            handler,
1503                            ctx,
1504                            engines,
1505                            metadata_types,
1506                            concrete_types,
1507                            arg.initial_type_id(),
1508                            p.type_id,
1509                        )
1510                    })
1511                    .collect::<Result<Vec<_>, _>>()?
1512            }),
1513            TypeInfo::Enum(decl_ref) => {
1514                let decl = decl_engine.get_enum(decl_ref);
1515                Some(
1516                    decl.generic_parameters
1517                        .iter()
1518                        .map(|p| {
1519                            let p = p
1520                                .as_type_parameter()
1521                                .expect("only works with type parameters");
1522                            generate_concrete_type_declaration(
1523                                handler,
1524                                ctx,
1525                                engines,
1526                                metadata_types,
1527                                concrete_types,
1528                                p.type_id,
1529                                p.type_id,
1530                            )
1531                        })
1532                        .collect::<Result<Vec<_>, _>>()?,
1533                )
1534            }
1535            TypeInfo::Struct(decl_ref) => {
1536                let decl = decl_engine.get_struct(decl_ref);
1537                Some(
1538                    decl.generic_parameters
1539                        .iter()
1540                        .map(|p| {
1541                            let p = p
1542                                .as_type_parameter()
1543                                .expect("only works with type parameters");
1544                            generate_concrete_type_declaration(
1545                                handler,
1546                                ctx,
1547                                engines,
1548                                metadata_types,
1549                                concrete_types,
1550                                p.type_id,
1551                                p.type_id,
1552                            )
1553                        })
1554                        .collect::<Result<Vec<_>, _>>()?,
1555                )
1556            }
1557            _ => None,
1558        })
1559    }
1560}
1561
1562impl TyFunctionDecl {
1563    pub(self) fn generate_abi_function(
1564        &self,
1565        handler: &Handler,
1566        ctx: &mut AbiContext,
1567        engines: &Engines,
1568        metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
1569        concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
1570    ) -> Result<program_abi::ABIFunction, ErrorEmitted> {
1571        let inputs = handler.scope(|handler| {
1572            self.parameters
1573                .iter()
1574                .map(|param| {
1575                    generate_concrete_type_declaration(
1576                        handler,
1577                        ctx,
1578                        engines,
1579                        metadata_types,
1580                        concrete_types,
1581                        param.type_argument.initial_type_id,
1582                        param.type_argument.type_id,
1583                    )
1584                    .map(|concrete_type_id| {
1585                        program_abi::TypeConcreteParameter {
1586                            name: param.name.to_string(),
1587                            concrete_type_id,
1588                        }
1589                    })
1590                })
1591                .collect::<Result<Vec<_>, ErrorEmitted>>()
1592        })?;
1593
1594        // Generate the JSON data for the function
1595        Ok(program_abi::ABIFunction {
1596            name: self.name.as_str().to_string(),
1597            inputs,
1598            output: generate_concrete_type_declaration(
1599                handler,
1600                ctx,
1601                engines,
1602                metadata_types,
1603                concrete_types,
1604                self.return_type.initial_type_id,
1605                self.return_type.type_id,
1606            )?,
1607            attributes: generate_attributes(&self.attributes),
1608        })
1609    }
1610}
1611
1612fn generate_attributes(attributes: &Attributes) -> Option<Vec<program_abi::Attribute>> {
1613    if attributes.is_empty() {
1614        None
1615    } else {
1616        Some(
1617            attributes
1618                .all()
1619                .map(|attr| program_abi::Attribute {
1620                    name: attr.name.to_string(),
1621                    arguments: attr.args.iter().map(|arg| arg.name.to_string()).collect(),
1622                })
1623                .collect(),
1624        )
1625    }
1626}
1627
1628impl GenericTypeParameter {
1629    /// Returns the initial type ID of a TypeParameter. Also updates the provided list of types to
1630    /// append the current TypeParameter as a `program_abi::TypeMetadataDeclaration`.
1631    pub(self) fn get_abi_type_parameter(
1632        &self,
1633        handler: &Handler,
1634        ctx: &mut AbiContext,
1635        engines: &Engines,
1636        metadata_types: &mut Vec<program_abi::TypeMetadataDeclaration>,
1637        concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
1638        metadata_types_to_add: &mut Vec<program_abi::TypeMetadataDeclaration>,
1639    ) -> Result<MetadataTypeId, ErrorEmitted> {
1640        let type_id = MetadataTypeId(self.initial_type_id.index());
1641        let type_parameter = program_abi::TypeMetadataDeclaration {
1642            metadata_type_id: type_id.clone(),
1643            type_field: self.initial_type_id.get_abi_type_str(
1644                handler,
1645                &ctx.to_str_context(),
1646                engines,
1647                self.type_id,
1648            )?,
1649            components: self.initial_type_id.get_abi_type_components(
1650                handler,
1651                ctx,
1652                engines,
1653                metadata_types,
1654                concrete_types,
1655                self.type_id,
1656                metadata_types_to_add,
1657            )?,
1658            type_parameters: None,
1659        };
1660        metadata_types_to_add.push(type_parameter);
1661        Ok(type_id)
1662    }
1663}