diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index e93d2e0242c..76366656f6d 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -27,6 +27,7 @@ use std::{ str::FromStr, }; use sway_core::{ + abi_generation::generate_json_abi_program, asm_generation::ProgramABI, decl_engine::{DeclEngine, DeclId}, fuel_prelude::{ @@ -36,7 +37,7 @@ use sway_core::{ language::{ lexed::LexedProgram, parsed::{ParseProgram, TreeType}, - ty, + ty::{self}, }, semantic_analysis::namespace, source_map::SourceMap, @@ -2523,7 +2524,7 @@ pub fn compile( let mut types = vec![]; ProgramABI::Fuel(time_expr!( "generate JSON ABI program", - typed_program.generate_json_abi_program(engines.te(), &mut types) + generate_json_abi_program(typed_program, engines.te(), &mut types) )) } BuildTarget::EVM => match &asm_res.value { diff --git a/sway-core/src/abi_generation/fuel_json_abi.rs b/sway-core/src/abi_generation/fuel_json_abi.rs new file mode 100644 index 00000000000..5ac42c7e7c3 --- /dev/null +++ b/sway-core/src/abi_generation/fuel_json_abi.rs @@ -0,0 +1,714 @@ +use fuel_abi_types::program_abi; +use sway_types::integer_bits::IntegerBits; + +use crate::{ + language::ty::{TyConstantDeclaration, TyFunctionDeclaration, TyProgram, TyProgramKind}, + transform::AttributesMap, + TypeArgument, TypeEngine, TypeId, TypeInfo, TypeParameter, +}; + +pub fn generate_json_abi_program( + program: &TyProgram, + type_engine: &TypeEngine, + types: &mut Vec, +) -> program_abi::ProgramABI { + match &program.kind { + TyProgramKind::Contract { abi_entries, .. } => { + let functions = abi_entries + .iter() + .map(|x| x.generate_json_abi_function(type_engine, types)) + .collect(); + let logged_types = generate_json_logged_types(program, type_engine, types); + let messages_types = generate_json_messages_types(program, type_engine, types); + let configurables = generate_json_configurables(program, type_engine, types); + program_abi::ProgramABI { + types: types.to_vec(), + functions, + logged_types: Some(logged_types), + messages_types: Some(messages_types), + configurables: Some(configurables), + } + } + TyProgramKind::Script { main_function, .. } + | TyProgramKind::Predicate { main_function, .. } => { + let functions = vec![main_function.generate_json_abi_function(type_engine, types)]; + let logged_types = generate_json_logged_types(program, type_engine, types); + let messages_types = generate_json_messages_types(program, type_engine, types); + let configurables = generate_json_configurables(program, type_engine, types); + program_abi::ProgramABI { + types: types.to_vec(), + functions, + logged_types: Some(logged_types), + messages_types: Some(messages_types), + configurables: Some(configurables), + } + } + _ => program_abi::ProgramABI { + types: vec![], + functions: vec![], + logged_types: None, + messages_types: None, + configurables: None, + }, + } +} + +fn generate_json_logged_types( + program: &TyProgram, + type_engine: &TypeEngine, + types: &mut Vec, +) -> Vec { + // A list of all `program_abi::TypeDeclaration`s needed for the logged types + let logged_types = program + .logged_types + .iter() + .map(|(_, type_id)| program_abi::TypeDeclaration { + type_id: type_id.index(), + type_field: type_id.get_json_type_str(type_engine, *type_id), + components: type_id.get_json_type_components(type_engine, types, *type_id), + type_parameters: type_id.get_json_type_parameters(type_engine, types, *type_id), + }) + .collect::>(); + + // Add the new types to `types` + types.extend(logged_types); + + // Generate the JSON data for the logged types + program + .logged_types + .iter() + .map(|(log_id, type_id)| program_abi::LoggedType { + log_id: **log_id as u64, + application: program_abi::TypeApplication { + name: "".to_string(), + type_id: type_id.index(), + type_arguments: type_id.get_json_type_arguments(type_engine, types, *type_id), + }, + }) + .collect() +} + +fn generate_json_messages_types( + program: &TyProgram, + type_engine: &TypeEngine, + types: &mut Vec, +) -> Vec { + // A list of all `program_abi::TypeDeclaration`s needed for the messages types + let messages_types = program + .messages_types + .iter() + .map(|(_, type_id)| program_abi::TypeDeclaration { + type_id: type_id.index(), + type_field: type_id.get_json_type_str(type_engine, *type_id), + components: type_id.get_json_type_components(type_engine, types, *type_id), + type_parameters: type_id.get_json_type_parameters(type_engine, types, *type_id), + }) + .collect::>(); + + // Add the new types to `types` + types.extend(messages_types); + + // Generate the JSON data for the messages types + program + .messages_types + .iter() + .map(|(message_id, type_id)| program_abi::MessageType { + message_id: **message_id as u64, + application: program_abi::TypeApplication { + name: "".to_string(), + type_id: type_id.index(), + type_arguments: type_id.get_json_type_arguments(type_engine, types, *type_id), + }, + }) + .collect() +} + +fn generate_json_configurables( + program: &TyProgram, + type_engine: &TypeEngine, + types: &mut Vec, +) -> Vec { + // A list of all `program_abi::TypeDeclaration`s needed for the configurables types + let configurables_types = program + .configurables + .iter() + .map( + |TyConstantDeclaration { return_type, .. }| program_abi::TypeDeclaration { + type_id: return_type.index(), + type_field: return_type.get_json_type_str(type_engine, *return_type), + components: return_type.get_json_type_components(type_engine, types, *return_type), + type_parameters: return_type.get_json_type_parameters( + type_engine, + types, + *return_type, + ), + }, + ) + .collect::>(); + + // Add the new types to `types` + types.extend(configurables_types); + + // Generate the JSON data for the configurables types + program + .configurables + .iter() + .map( + |TyConstantDeclaration { + name, return_type, .. + }| program_abi::Configurable { + name: name.to_string(), + application: program_abi::TypeApplication { + name: "".to_string(), + type_id: return_type.index(), + type_arguments: return_type.get_json_type_arguments( + type_engine, + types, + *return_type, + ), + }, + offset: 0, + }, + ) + .collect() +} + +impl TypeId { + /// Gives back a string that represents the type, considering what it resolves to + pub(self) fn get_json_type_str( + &self, + type_engine: &TypeEngine, + resolved_type_id: TypeId, + ) -> String { + if self.is_generic_parameter(type_engine, resolved_type_id) { + format!( + "generic {}", + type_engine.get(*self).json_abi_str(type_engine) + ) + } else { + match (type_engine.get(*self), type_engine.get(resolved_type_id)) { + (TypeInfo::Custom { .. }, TypeInfo::Struct { .. }) => { + format!( + "struct {}", + type_engine.get(*self).json_abi_str(type_engine) + ) + } + (TypeInfo::Custom { .. }, TypeInfo::Enum { .. }) => { + format!("enum {}", type_engine.get(*self).json_abi_str(type_engine)) + } + (TypeInfo::Tuple(fields), TypeInfo::Tuple(resolved_fields)) => { + assert_eq!(fields.len(), resolved_fields.len()); + let field_strs = fields + .iter() + .map(|_| "_".to_string()) + .collect::>(); + format!("({})", field_strs.join(", ")) + } + (TypeInfo::Array(_, count), TypeInfo::Array(_, resolved_count)) => { + assert_eq!(count.val(), resolved_count.val()); + format!("[_; {}]", count.val()) + } + (TypeInfo::Custom { .. }, _) => { + format!( + "generic {}", + type_engine.get(*self).json_abi_str(type_engine) + ) + } + _ => type_engine.get(*self).json_abi_str(type_engine), + } + } + } + + /// Return the type parameters of a given (potentially generic) type while considering what it + /// actually resolves to. These parameters are essentially of type of `usize` which are + /// basically the IDs of some set of `program_abi::TypeDeclaration`s. The method below also + /// updates the provide list of `program_abi::TypeDeclaration`s to add the newly discovered + /// types. + pub(self) fn get_json_type_parameters( + &self, + type_engine: &TypeEngine, + types: &mut Vec, + resolved_type_id: TypeId, + ) -> Option> { + match self.is_generic_parameter(type_engine, resolved_type_id) { + true => None, + false => resolved_type_id.get_type_parameters(type_engine).map(|v| { + v.iter() + .map(|v| v.get_json_type_parameter(type_engine, types)) + .collect::>() + }), + } + } + /// Return the components of a given (potentially generic) type while considering what it + /// actually resolves to. These components are essentially of type of + /// `program_abi::TypeApplication`. The method below also updates the provided list of + /// `program_abi::TypeDeclaration`s to add the newly discovered types. + pub(self) fn get_json_type_components( + &self, + type_engine: &TypeEngine, + types: &mut Vec, + resolved_type_id: TypeId, + ) -> Option> { + match type_engine.get(*self) { + TypeInfo::Enum { variant_types, .. } => { + // A list of all `program_abi::TypeDeclaration`s needed for the enum variants + let variants = variant_types + .iter() + .map(|x| program_abi::TypeDeclaration { + type_id: x.initial_type_id.index(), + type_field: x.initial_type_id.get_json_type_str(type_engine, x.type_id), + components: x.initial_type_id.get_json_type_components( + type_engine, + types, + x.type_id, + ), + type_parameters: x.initial_type_id.get_json_type_parameters( + type_engine, + types, + x.type_id, + ), + }) + .collect::>(); + types.extend(variants); + + // Generate the JSON data for the enum. This is basically a list of + // `program_abi::TypeApplication`s + Some( + variant_types + .iter() + .map(|x| program_abi::TypeApplication { + name: x.name.to_string(), + type_id: x.initial_type_id.index(), + type_arguments: x.initial_type_id.get_json_type_arguments( + type_engine, + types, + x.type_id, + ), + }) + .collect(), + ) + } + TypeInfo::Struct { fields, .. } => { + // A list of all `program_abi::TypeDeclaration`s needed for the struct fields + let field_types = fields + .iter() + .map(|x| program_abi::TypeDeclaration { + type_id: x.initial_type_id.index(), + type_field: x.initial_type_id.get_json_type_str(type_engine, x.type_id), + components: x.initial_type_id.get_json_type_components( + type_engine, + types, + x.type_id, + ), + type_parameters: x.initial_type_id.get_json_type_parameters( + type_engine, + types, + x.type_id, + ), + }) + .collect::>(); + types.extend(field_types); + + // Generate the JSON data for the struct. This is basically a list of + // `program_abi::TypeApplication`s + Some( + fields + .iter() + .map(|x| program_abi::TypeApplication { + name: x.name.to_string(), + type_id: x.initial_type_id.index(), + type_arguments: x.initial_type_id.get_json_type_arguments( + type_engine, + types, + x.type_id, + ), + }) + .collect(), + ) + } + TypeInfo::Array(..) => { + if let TypeInfo::Array(elem_ty, _) = type_engine.get(resolved_type_id) { + // The `program_abi::TypeDeclaration`s needed for the array element type + let elem_json_ty = program_abi::TypeDeclaration { + type_id: elem_ty.initial_type_id.index(), + type_field: elem_ty + .initial_type_id + .get_json_type_str(type_engine, elem_ty.type_id), + components: elem_ty.initial_type_id.get_json_type_components( + type_engine, + types, + elem_ty.type_id, + ), + type_parameters: elem_ty.initial_type_id.get_json_type_parameters( + type_engine, + types, + elem_ty.type_id, + ), + }; + types.push(elem_json_ty); + + // Generate the JSON data for the array. This is basically a single + // `program_abi::TypeApplication` for the array element type + Some(vec![program_abi::TypeApplication { + name: "__array_element".to_string(), + type_id: elem_ty.initial_type_id.index(), + type_arguments: elem_ty.initial_type_id.get_json_type_arguments( + type_engine, + types, + elem_ty.type_id, + ), + }]) + } else { + unreachable!(); + } + } + TypeInfo::Tuple(_) => { + if let TypeInfo::Tuple(fields) = type_engine.get(resolved_type_id) { + // A list of all `program_abi::TypeDeclaration`s needed for the tuple fields + let fields_types = fields + .iter() + .map(|x| program_abi::TypeDeclaration { + type_id: x.initial_type_id.index(), + type_field: x.initial_type_id.get_json_type_str(type_engine, x.type_id), + components: x.initial_type_id.get_json_type_components( + type_engine, + types, + x.type_id, + ), + type_parameters: x.initial_type_id.get_json_type_parameters( + type_engine, + types, + x.type_id, + ), + }) + .collect::>(); + types.extend(fields_types); + + // Generate the JSON data for the tuple. This is basically a list of + // `program_abi::TypeApplication`s + Some( + fields + .iter() + .map(|x| program_abi::TypeApplication { + name: "__tuple_element".to_string(), + type_id: x.initial_type_id.index(), + type_arguments: x.initial_type_id.get_json_type_arguments( + type_engine, + types, + x.type_id, + ), + }) + .collect(), + ) + } else { + unreachable!() + } + } + TypeInfo::Custom { type_arguments, .. } => { + if !self.is_generic_parameter(type_engine, resolved_type_id) { + // A list of all `program_abi::TypeDeclaration`s needed for the type arguments + let type_args = type_arguments + .unwrap_or_default() + .iter() + .zip( + resolved_type_id + .get_type_parameters(type_engine) + .unwrap_or_default() + .iter(), + ) + .map(|(v, p)| program_abi::TypeDeclaration { + type_id: v.initial_type_id.index(), + type_field: v.initial_type_id.get_json_type_str(type_engine, p.type_id), + components: v.initial_type_id.get_json_type_components( + type_engine, + types, + p.type_id, + ), + type_parameters: v.initial_type_id.get_json_type_parameters( + type_engine, + types, + p.type_id, + ), + }) + .collect::>(); + types.extend(type_args); + + resolved_type_id.get_json_type_components(type_engine, types, resolved_type_id) + } else { + None + } + } + _ => None, + } + } + + /// Return the type arguments of a given (potentially generic) type while considering what it + /// actually resolves to. These arguments are essentially of type of + /// `program_abi::TypeApplication`. The method below also updates the provided list of + /// `program_abi::TypeDeclaration`s to add the newly discovered types. + pub(self) fn get_json_type_arguments( + &self, + type_engine: &TypeEngine, + types: &mut Vec, + resolved_type_id: TypeId, + ) -> Option> { + let resolved_params = resolved_type_id.get_type_parameters(type_engine); + match type_engine.get(*self) { + TypeInfo::Custom { + type_arguments: Some(type_arguments), + .. + } => (!type_arguments.is_empty()).then_some({ + let resolved_params = resolved_params.unwrap_or_default(); + let json_type_arguments = type_arguments + .iter() + .zip(resolved_params.iter()) + .map(|(v, p)| program_abi::TypeDeclaration { + type_id: v.initial_type_id.index(), + type_field: v.initial_type_id.get_json_type_str(type_engine, p.type_id), + components: v.initial_type_id.get_json_type_components( + type_engine, + types, + p.type_id, + ), + type_parameters: v.initial_type_id.get_json_type_parameters( + type_engine, + types, + p.type_id, + ), + }) + .collect::>(); + types.extend(json_type_arguments); + + type_arguments + .iter() + .map(|arg| program_abi::TypeApplication { + name: "".to_string(), + type_id: arg.initial_type_id.index(), + type_arguments: arg.initial_type_id.get_json_type_arguments( + type_engine, + types, + arg.type_id, + ), + }) + .collect::>() + }), + TypeInfo::Enum { + type_parameters, .. + } + | TypeInfo::Struct { + type_parameters, .. + } => { + // Here, type_id for each type parameter should contain resolved types + let json_type_arguments = type_parameters + .iter() + .map(|v| program_abi::TypeDeclaration { + type_id: v.type_id.index(), + type_field: v.type_id.get_json_type_str(type_engine, v.type_id), + components: v.type_id.get_json_type_components( + type_engine, + types, + v.type_id, + ), + type_parameters: v.type_id.get_json_type_parameters( + type_engine, + types, + v.type_id, + ), + }) + .collect::>(); + types.extend(json_type_arguments); + + Some( + type_parameters + .iter() + .map(|arg| program_abi::TypeApplication { + name: "".to_string(), + type_id: arg.type_id.index(), + type_arguments: arg.type_id.get_json_type_arguments( + type_engine, + types, + arg.type_id, + ), + }) + .collect::>(), + ) + } + _ => None, + } + } +} + +impl TypeInfo { + pub fn json_abi_str(&self, type_engine: &TypeEngine) -> String { + use TypeInfo::*; + match self { + Unknown => "unknown".into(), + UnknownGeneric { name, .. } => name.to_string(), + TypeInfo::Placeholder(_) => "_".to_string(), + Str(x) => format!("str[{}]", x.val()), + UnsignedInteger(x) => match x { + IntegerBits::Eight => "u8", + IntegerBits::Sixteen => "u16", + IntegerBits::ThirtyTwo => "u32", + IntegerBits::SixtyFour => "u64", + } + .into(), + Boolean => "bool".into(), + Custom { name, .. } => name.to_string(), + Tuple(fields) => { + let field_strs = fields + .iter() + .map(|field| field.json_abi_str(type_engine)) + .collect::>(); + format!("({})", field_strs.join(", ")) + } + SelfType => "Self".into(), + B256 => "b256".into(), + Numeric => "u64".into(), // u64 is the default + Contract => "contract".into(), + ErrorRecovery => "unknown due to error".into(), + Enum { name, .. } => { + format!("enum {name}") + } + Struct { name, .. } => { + format!("struct {name}") + } + ContractCaller { abi_name, .. } => { + format!("contract caller {abi_name}") + } + Array(elem_ty, length) => { + format!("[{}; {}]", elem_ty.json_abi_str(type_engine), length.val()) + } + Storage { .. } => "contract storage".into(), + RawUntypedPtr => "raw untyped ptr".into(), + RawUntypedSlice => "raw untyped slice".into(), + } + } +} + +impl TyFunctionDeclaration { + pub(self) fn generate_json_abi_function( + &self, + type_engine: &TypeEngine, + types: &mut Vec, + ) -> program_abi::ABIFunction { + // A list of all `program_abi::TypeDeclaration`s needed for inputs + let input_types = self + .parameters + .iter() + .map(|x| program_abi::TypeDeclaration { + type_id: x.initial_type_id.index(), + type_field: x.initial_type_id.get_json_type_str(type_engine, x.type_id), + components: x.initial_type_id.get_json_type_components( + type_engine, + types, + x.type_id, + ), + type_parameters: x + .type_id + .get_json_type_parameters(type_engine, types, x.type_id), + }) + .collect::>(); + + // The single `program_abi::TypeDeclaration` needed for the output + let output_type = program_abi::TypeDeclaration { + type_id: self.initial_return_type.index(), + type_field: self + .initial_return_type + .get_json_type_str(type_engine, self.return_type), + components: self.return_type.get_json_type_components( + type_engine, + types, + self.return_type, + ), + type_parameters: self.return_type.get_json_type_parameters( + type_engine, + types, + self.return_type, + ), + }; + + // Add the new types to `types` + types.extend(input_types); + types.push(output_type); + + // Generate the JSON data for the function + program_abi::ABIFunction { + name: self.name.as_str().to_string(), + inputs: self + .parameters + .iter() + .map(|x| program_abi::TypeApplication { + name: x.name.to_string(), + type_id: x.initial_type_id.index(), + type_arguments: x.initial_type_id.get_json_type_arguments( + type_engine, + types, + x.type_id, + ), + }) + .collect(), + output: program_abi::TypeApplication { + name: "".to_string(), + type_id: self.initial_return_type.index(), + type_arguments: self.initial_return_type.get_json_type_arguments( + type_engine, + types, + self.return_type, + ), + }, + attributes: generate_json_abi_attributes_map(&self.attributes), + } + } +} + +fn generate_json_abi_attributes_map( + attr_map: &AttributesMap, +) -> Option> { + if attr_map.is_empty() { + None + } else { + Some( + attr_map + .iter() + .flat_map(|(_attr_kind, attrs)| { + attrs.iter().map(|attr| program_abi::Attribute { + name: attr.name.to_string(), + arguments: attr.args.iter().map(|arg| arg.to_string()).collect(), + }) + }) + .collect(), + ) + } +} + +impl TypeParameter { + /// Returns the initial type ID of a TypeParameter. Also updates the provided list of types to + /// append the current TypeParameter as a `program_abi::TypeDeclaration`. + pub(self) fn get_json_type_parameter( + &self, + type_engine: &TypeEngine, + types: &mut Vec, + ) -> usize { + let type_parameter = program_abi::TypeDeclaration { + type_id: self.initial_type_id.index(), + type_field: self + .initial_type_id + .get_json_type_str(type_engine, self.type_id), + components: self.initial_type_id.get_json_type_components( + type_engine, + types, + self.type_id, + ), + type_parameters: None, + }; + types.push(type_parameter); + self.initial_type_id.index() + } +} + +impl TypeArgument { + pub(self) fn json_abi_str(&self, type_engine: &TypeEngine) -> String { + type_engine.get(self.type_id).json_abi_str(type_engine) + } +} diff --git a/sway-core/src/abi_generation/mod.rs b/sway-core/src/abi_generation/mod.rs new file mode 100644 index 00000000000..d0bd9cb6942 --- /dev/null +++ b/sway-core/src/abi_generation/mod.rs @@ -0,0 +1,2 @@ +mod fuel_json_abi; +pub use fuel_json_abi::*; diff --git a/sway-core/src/language/ty/declaration/function.rs b/sway-core/src/language/ty/declaration/function.rs index 0d40d1d86f0..c1831376051 100644 --- a/sway-core/src/language/ty/declaration/function.rs +++ b/sway-core/src/language/ty/declaration/function.rs @@ -9,8 +9,6 @@ use crate::{ type_system::*, }; -use fuel_abi_types::program_abi; - use sway_types::{ constants::{INLINE_ALWAYS_NAME, INLINE_NEVER_NAME}, Ident, Span, Spanned, @@ -297,80 +295,6 @@ impl TyFunctionDeclaration { ) } - pub(crate) fn generate_json_abi_function( - &self, - type_engine: &TypeEngine, - types: &mut Vec, - ) -> program_abi::ABIFunction { - // A list of all `program_abi::TypeDeclaration`s needed for inputs - let input_types = self - .parameters - .iter() - .map(|x| program_abi::TypeDeclaration { - type_id: x.initial_type_id.index(), - type_field: x.initial_type_id.get_json_type_str(type_engine, x.type_id), - components: x.initial_type_id.get_json_type_components( - type_engine, - types, - x.type_id, - ), - type_parameters: x - .type_id - .get_json_type_parameters(type_engine, types, x.type_id), - }) - .collect::>(); - - // The single `program_abi::TypeDeclaration` needed for the output - let output_type = program_abi::TypeDeclaration { - type_id: self.initial_return_type.index(), - type_field: self - .initial_return_type - .get_json_type_str(type_engine, self.return_type), - components: self.return_type.get_json_type_components( - type_engine, - types, - self.return_type, - ), - type_parameters: self.return_type.get_json_type_parameters( - type_engine, - types, - self.return_type, - ), - }; - - // Add the new types to `types` - types.extend(input_types); - types.push(output_type); - - // Generate the JSON data for the function - program_abi::ABIFunction { - name: self.name.as_str().to_string(), - inputs: self - .parameters - .iter() - .map(|x| program_abi::TypeApplication { - name: x.name.to_string(), - type_id: x.initial_type_id.index(), - type_arguments: x.initial_type_id.get_json_type_arguments( - type_engine, - types, - x.type_id, - ), - }) - .collect(), - output: program_abi::TypeApplication { - name: "".to_string(), - type_id: self.initial_return_type.index(), - type_arguments: self.initial_return_type.get_json_type_arguments( - type_engine, - types, - self.return_type, - ), - }, - attributes: transform::generate_json_abi_attributes_map(&self.attributes), - } - } - /// Whether or not this function is the default entry point. pub fn is_main_entry(&self) -> bool { // NOTE: We may want to make this check more sophisticated or customisable in the future, diff --git a/sway-core/src/language/ty/program.rs b/sway-core/src/language/ty/program.rs index 9e69d08fde8..90eef223a65 100644 --- a/sway-core/src/language/ty/program.rs +++ b/sway-core/src/language/ty/program.rs @@ -11,8 +11,6 @@ use crate::{ use sway_error::error::CompileError; use sway_types::*; -use fuel_abi_types::program_abi; - #[derive(Debug, Clone)] pub struct TyProgram { pub kind: TyProgramKind, @@ -304,9 +302,22 @@ impl TyProgram { ) } + /// All test function declarations within the program. + pub fn test_fns<'a: 'b, 'b>( + &'b self, + decl_engine: &'a DeclEngine, + ) -> impl '_ + Iterator { + self.root + .submodules_recursive() + .flat_map(|(_, submod)| submod.module.test_fns(decl_engine)) + .chain(self.root.test_fns(decl_engine)) + } +} + +impl CollectTypesMetadata for TyProgram { /// Collect various type information such as unresolved types and types of logged data - pub(crate) fn collect_types_metadata( - &mut self, + fn collect_types_metadata( + &self, ctx: &mut CollectTypesMetadataContext, ) -> CompileResult> { let mut warnings = vec![]; @@ -419,184 +430,6 @@ impl TyProgram { err(warnings, errors) } } - - pub fn generate_json_abi_program( - &self, - type_engine: &TypeEngine, - types: &mut Vec, - ) -> program_abi::ProgramABI { - match &self.kind { - TyProgramKind::Contract { abi_entries, .. } => { - let functions = abi_entries - .iter() - .map(|x| x.generate_json_abi_function(type_engine, types)) - .collect(); - let logged_types = self.generate_json_logged_types(type_engine, types); - let messages_types = self.generate_json_messages_types(type_engine, types); - let configurables = self.generate_json_configurables(type_engine, types); - program_abi::ProgramABI { - types: types.to_vec(), - functions, - logged_types: Some(logged_types), - messages_types: Some(messages_types), - configurables: Some(configurables), - } - } - TyProgramKind::Script { main_function, .. } - | TyProgramKind::Predicate { main_function, .. } => { - let functions = vec![main_function.generate_json_abi_function(type_engine, types)]; - let logged_types = self.generate_json_logged_types(type_engine, types); - let messages_types = self.generate_json_messages_types(type_engine, types); - let configurables = self.generate_json_configurables(type_engine, types); - program_abi::ProgramABI { - types: types.to_vec(), - functions, - logged_types: Some(logged_types), - messages_types: Some(messages_types), - configurables: Some(configurables), - } - } - _ => program_abi::ProgramABI { - types: vec![], - functions: vec![], - logged_types: None, - messages_types: None, - configurables: None, - }, - } - } - - fn generate_json_logged_types( - &self, - type_engine: &TypeEngine, - types: &mut Vec, - ) -> Vec { - // A list of all `program_abi::TypeDeclaration`s needed for the logged types - let logged_types = self - .logged_types - .iter() - .map(|(_, type_id)| program_abi::TypeDeclaration { - type_id: type_id.index(), - type_field: type_id.get_json_type_str(type_engine, *type_id), - components: type_id.get_json_type_components(type_engine, types, *type_id), - type_parameters: type_id.get_json_type_parameters(type_engine, types, *type_id), - }) - .collect::>(); - - // Add the new types to `types` - types.extend(logged_types); - - // Generate the JSON data for the logged types - self.logged_types - .iter() - .map(|(log_id, type_id)| program_abi::LoggedType { - log_id: **log_id as u64, - application: program_abi::TypeApplication { - name: "".to_string(), - type_id: type_id.index(), - type_arguments: type_id.get_json_type_arguments(type_engine, types, *type_id), - }, - }) - .collect() - } - - fn generate_json_messages_types( - &self, - type_engine: &TypeEngine, - types: &mut Vec, - ) -> Vec { - // A list of all `program_abi::TypeDeclaration`s needed for the messages types - let messages_types = self - .messages_types - .iter() - .map(|(_, type_id)| program_abi::TypeDeclaration { - type_id: type_id.index(), - type_field: type_id.get_json_type_str(type_engine, *type_id), - components: type_id.get_json_type_components(type_engine, types, *type_id), - type_parameters: type_id.get_json_type_parameters(type_engine, types, *type_id), - }) - .collect::>(); - - // Add the new types to `types` - types.extend(messages_types); - - // Generate the JSON data for the messages types - self.messages_types - .iter() - .map(|(message_id, type_id)| program_abi::MessageType { - message_id: **message_id as u64, - application: program_abi::TypeApplication { - name: "".to_string(), - type_id: type_id.index(), - type_arguments: type_id.get_json_type_arguments(type_engine, types, *type_id), - }, - }) - .collect() - } - - fn generate_json_configurables( - &self, - type_engine: &TypeEngine, - types: &mut Vec, - ) -> Vec { - // A list of all `program_abi::TypeDeclaration`s needed for the configurables types - let configurables_types = self - .configurables - .iter() - .map( - |TyConstantDeclaration { return_type, .. }| program_abi::TypeDeclaration { - type_id: return_type.index(), - type_field: return_type.get_json_type_str(type_engine, *return_type), - components: return_type.get_json_type_components( - type_engine, - types, - *return_type, - ), - type_parameters: return_type.get_json_type_parameters( - type_engine, - types, - *return_type, - ), - }, - ) - .collect::>(); - - // Add the new types to `types` - types.extend(configurables_types); - - // Generate the JSON data for the configurables types - self.configurables - .iter() - .map( - |TyConstantDeclaration { - name, return_type, .. - }| program_abi::Configurable { - name: name.to_string(), - application: program_abi::TypeApplication { - name: "".to_string(), - type_id: return_type.index(), - type_arguments: return_type.get_json_type_arguments( - type_engine, - types, - *return_type, - ), - }, - offset: 0, - }, - ) - .collect() - } - - /// All test function declarations within the program. - pub fn test_fns<'a: 'b, 'b>( - &'b self, - decl_engine: &'a DeclEngine, - ) -> impl '_ + Iterator { - self.root - .submodules_recursive() - .flat_map(|(_, submod)| submod.module.test_fns(decl_engine)) - .chain(self.root.test_fns(decl_engine)) - } } #[derive(Clone, Debug)] diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index 20e50b2582f..193e879493c 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -1,6 +1,7 @@ #[macro_use] pub mod error; +pub mod abi_generation; pub mod asm_generation; mod asm_lang; mod build_config; diff --git a/sway-core/src/transform/attribute.rs b/sway-core/src/transform/attribute.rs index 5106a74a4bd..133f19059d8 100644 --- a/sway-core/src/transform/attribute.rs +++ b/sway-core/src/transform/attribute.rs @@ -22,8 +22,6 @@ use sway_types::{Ident, Span}; -use fuel_abi_types::program_abi; - use std::{collections::HashMap, sync::Arc}; /// An attribute has a name (i.e "doc", "storage"), @@ -81,23 +79,3 @@ impl std::ops::Deref for AttributesMap { &self.0 } } - -pub(crate) fn generate_json_abi_attributes_map( - attr_map: &AttributesMap, -) -> Option> { - if attr_map.is_empty() { - None - } else { - Some( - attr_map - .iter() - .flat_map(|(_attr_kind, attrs)| { - attrs.iter().map(|attr| program_abi::Attribute { - name: attr.name.to_string(), - arguments: attr.args.iter().map(|arg| arg.to_string()).collect(), - }) - }) - .collect(), - ) - } -} diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index 35442446bda..4518cea2a79 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -1,8 +1,6 @@ use super::*; use crate::engine_threading::*; -use fuel_abi_types::program_abi; - use std::fmt; /// A identifier to uniquely refer to our type terms @@ -324,372 +322,4 @@ impl TypeId { _ => false, } } - - /// Return the components of a given (potentially generic) type while considering what it - /// actually resolves to. These components are essentially of type of - /// `program_abi::TypeApplication`. The method below also updates the provided list of - /// `program_abi::TypeDeclaration`s to add the newly discovered types. - pub(crate) fn get_json_type_components( - &self, - type_engine: &TypeEngine, - types: &mut Vec, - resolved_type_id: TypeId, - ) -> Option> { - match type_engine.get(*self) { - TypeInfo::Enum { variant_types, .. } => { - // A list of all `program_abi::TypeDeclaration`s needed for the enum variants - let variants = variant_types - .iter() - .map(|x| program_abi::TypeDeclaration { - type_id: x.initial_type_id.index(), - type_field: x.initial_type_id.get_json_type_str(type_engine, x.type_id), - components: x.initial_type_id.get_json_type_components( - type_engine, - types, - x.type_id, - ), - type_parameters: x.initial_type_id.get_json_type_parameters( - type_engine, - types, - x.type_id, - ), - }) - .collect::>(); - types.extend(variants); - - // Generate the JSON data for the enum. This is basically a list of - // `program_abi::TypeApplication`s - Some( - variant_types - .iter() - .map(|x| program_abi::TypeApplication { - name: x.name.to_string(), - type_id: x.initial_type_id.index(), - type_arguments: x.initial_type_id.get_json_type_arguments( - type_engine, - types, - x.type_id, - ), - }) - .collect(), - ) - } - TypeInfo::Struct { fields, .. } => { - // A list of all `program_abi::TypeDeclaration`s needed for the struct fields - let field_types = fields - .iter() - .map(|x| program_abi::TypeDeclaration { - type_id: x.initial_type_id.index(), - type_field: x.initial_type_id.get_json_type_str(type_engine, x.type_id), - components: x.initial_type_id.get_json_type_components( - type_engine, - types, - x.type_id, - ), - type_parameters: x.initial_type_id.get_json_type_parameters( - type_engine, - types, - x.type_id, - ), - }) - .collect::>(); - types.extend(field_types); - - // Generate the JSON data for the struct. This is basically a list of - // `program_abi::TypeApplication`s - Some( - fields - .iter() - .map(|x| program_abi::TypeApplication { - name: x.name.to_string(), - type_id: x.initial_type_id.index(), - type_arguments: x.initial_type_id.get_json_type_arguments( - type_engine, - types, - x.type_id, - ), - }) - .collect(), - ) - } - TypeInfo::Array(..) => { - if let TypeInfo::Array(elem_ty, _) = type_engine.get(resolved_type_id) { - // The `program_abi::TypeDeclaration`s needed for the array element type - let elem_json_ty = program_abi::TypeDeclaration { - type_id: elem_ty.initial_type_id.index(), - type_field: elem_ty - .initial_type_id - .get_json_type_str(type_engine, elem_ty.type_id), - components: elem_ty.initial_type_id.get_json_type_components( - type_engine, - types, - elem_ty.type_id, - ), - type_parameters: elem_ty.initial_type_id.get_json_type_parameters( - type_engine, - types, - elem_ty.type_id, - ), - }; - types.push(elem_json_ty); - - // Generate the JSON data for the array. This is basically a single - // `program_abi::TypeApplication` for the array element type - Some(vec![program_abi::TypeApplication { - name: "__array_element".to_string(), - type_id: elem_ty.initial_type_id.index(), - type_arguments: elem_ty.initial_type_id.get_json_type_arguments( - type_engine, - types, - elem_ty.type_id, - ), - }]) - } else { - unreachable!(); - } - } - TypeInfo::Tuple(_) => { - if let TypeInfo::Tuple(fields) = type_engine.get(resolved_type_id) { - // A list of all `program_abi::TypeDeclaration`s needed for the tuple fields - let fields_types = fields - .iter() - .map(|x| program_abi::TypeDeclaration { - type_id: x.initial_type_id.index(), - type_field: x.initial_type_id.get_json_type_str(type_engine, x.type_id), - components: x.initial_type_id.get_json_type_components( - type_engine, - types, - x.type_id, - ), - type_parameters: x.initial_type_id.get_json_type_parameters( - type_engine, - types, - x.type_id, - ), - }) - .collect::>(); - types.extend(fields_types); - - // Generate the JSON data for the tuple. This is basically a list of - // `program_abi::TypeApplication`s - Some( - fields - .iter() - .map(|x| program_abi::TypeApplication { - name: "__tuple_element".to_string(), - type_id: x.initial_type_id.index(), - type_arguments: x.initial_type_id.get_json_type_arguments( - type_engine, - types, - x.type_id, - ), - }) - .collect(), - ) - } else { - unreachable!() - } - } - TypeInfo::Custom { type_arguments, .. } => { - if !self.is_generic_parameter(type_engine, resolved_type_id) { - // A list of all `program_abi::TypeDeclaration`s needed for the type arguments - let type_args = type_arguments - .unwrap_or_default() - .iter() - .zip( - resolved_type_id - .get_type_parameters(type_engine) - .unwrap_or_default() - .iter(), - ) - .map(|(v, p)| program_abi::TypeDeclaration { - type_id: v.initial_type_id.index(), - type_field: v.initial_type_id.get_json_type_str(type_engine, p.type_id), - components: v.initial_type_id.get_json_type_components( - type_engine, - types, - p.type_id, - ), - type_parameters: v.initial_type_id.get_json_type_parameters( - type_engine, - types, - p.type_id, - ), - }) - .collect::>(); - types.extend(type_args); - - resolved_type_id.get_json_type_components(type_engine, types, resolved_type_id) - } else { - None - } - } - _ => None, - } - } - - /// Return the type parameters of a given (potentially generic) type while considering what it - /// actually resolves to. These parameters are essentially of type of `usize` which are - /// basically the IDs of some set of `program_abi::TypeDeclaration`s. The method below also - /// updates the provide list of `program_abi::TypeDeclaration`s to add the newly discovered - /// types. - pub(crate) fn get_json_type_parameters( - &self, - type_engine: &TypeEngine, - types: &mut Vec, - resolved_type_id: TypeId, - ) -> Option> { - match self.is_generic_parameter(type_engine, resolved_type_id) { - true => None, - false => resolved_type_id.get_type_parameters(type_engine).map(|v| { - v.iter() - .map(|v| v.get_json_type_parameter(type_engine, types)) - .collect::>() - }), - } - } - - /// Return the type arguments of a given (potentially generic) type while considering what it - /// actually resolves to. These arguments are essentially of type of - /// `program_abi::TypeApplication`. The method below also updates the provided list of - /// `program_abi::TypeDeclaration`s to add the newly discovered types. - pub(crate) fn get_json_type_arguments( - &self, - type_engine: &TypeEngine, - types: &mut Vec, - resolved_type_id: TypeId, - ) -> Option> { - let resolved_params = resolved_type_id.get_type_parameters(type_engine); - match type_engine.get(*self) { - TypeInfo::Custom { - type_arguments: Some(type_arguments), - .. - } => (!type_arguments.is_empty()).then_some({ - let resolved_params = resolved_params.unwrap_or_default(); - let json_type_arguments = type_arguments - .iter() - .zip(resolved_params.iter()) - .map(|(v, p)| program_abi::TypeDeclaration { - type_id: v.initial_type_id.index(), - type_field: v.initial_type_id.get_json_type_str(type_engine, p.type_id), - components: v.initial_type_id.get_json_type_components( - type_engine, - types, - p.type_id, - ), - type_parameters: v.initial_type_id.get_json_type_parameters( - type_engine, - types, - p.type_id, - ), - }) - .collect::>(); - types.extend(json_type_arguments); - - type_arguments - .iter() - .map(|arg| program_abi::TypeApplication { - name: "".to_string(), - type_id: arg.initial_type_id.index(), - type_arguments: arg.initial_type_id.get_json_type_arguments( - type_engine, - types, - arg.type_id, - ), - }) - .collect::>() - }), - TypeInfo::Enum { - type_parameters, .. - } - | TypeInfo::Struct { - type_parameters, .. - } => { - // Here, type_id for each type parameter should contain resolved types - let json_type_arguments = type_parameters - .iter() - .map(|v| program_abi::TypeDeclaration { - type_id: v.type_id.index(), - type_field: v.type_id.get_json_type_str(type_engine, v.type_id), - components: v.type_id.get_json_type_components( - type_engine, - types, - v.type_id, - ), - type_parameters: v.type_id.get_json_type_parameters( - type_engine, - types, - v.type_id, - ), - }) - .collect::>(); - types.extend(json_type_arguments); - - Some( - type_parameters - .iter() - .map(|arg| program_abi::TypeApplication { - name: "".to_string(), - type_id: arg.type_id.index(), - type_arguments: arg.type_id.get_json_type_arguments( - type_engine, - types, - arg.type_id, - ), - }) - .collect::>(), - ) - } - _ => None, - } - } - - pub fn json_abi_str(&self, type_engine: &TypeEngine) -> String { - type_engine.get(*self).json_abi_str(type_engine) - } - - /// Gives back a string that represents the type, considering what it resolves to - pub(crate) fn get_json_type_str( - &self, - type_engine: &TypeEngine, - resolved_type_id: TypeId, - ) -> String { - if self.is_generic_parameter(type_engine, resolved_type_id) { - format!( - "generic {}", - type_engine.get(*self).json_abi_str(type_engine) - ) - } else { - match (type_engine.get(*self), type_engine.get(resolved_type_id)) { - (TypeInfo::Custom { .. }, TypeInfo::Struct { .. }) => { - format!( - "struct {}", - type_engine.get(*self).json_abi_str(type_engine) - ) - } - (TypeInfo::Custom { .. }, TypeInfo::Enum { .. }) => { - format!("enum {}", type_engine.get(*self).json_abi_str(type_engine)) - } - (TypeInfo::Tuple(fields), TypeInfo::Tuple(resolved_fields)) => { - assert_eq!(fields.len(), resolved_fields.len()); - let field_strs = fields - .iter() - .map(|_| "_".to_string()) - .collect::>(); - format!("({})", field_strs.join(", ")) - } - (TypeInfo::Array(_, count), TypeInfo::Array(_, resolved_count)) => { - assert_eq!(count.val(), resolved_count.val()); - format!("[_; {}]", count.val()) - } - (TypeInfo::Custom { .. }, _) => { - format!( - "generic {}", - type_engine.get(*self).json_abi_str(type_engine) - ) - } - _ => type_engine.get(*self).json_abi_str(type_engine), - } - } - } } diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index 384f95edcb7..d96e8c0e153 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -541,52 +541,6 @@ impl UnconstrainedTypeParameters for TypeInfo { } impl TypeInfo { - pub fn json_abi_str(&self, type_engine: &TypeEngine) -> String { - use TypeInfo::*; - match self { - Unknown => "unknown".into(), - UnknownGeneric { name, .. } => name.to_string(), - TypeInfo::Placeholder(_) => "_".to_string(), - Str(x) => format!("str[{}]", x.val()), - UnsignedInteger(x) => match x { - IntegerBits::Eight => "u8", - IntegerBits::Sixteen => "u16", - IntegerBits::ThirtyTwo => "u32", - IntegerBits::SixtyFour => "u64", - } - .into(), - Boolean => "bool".into(), - Custom { name, .. } => name.to_string(), - Tuple(fields) => { - let field_strs = fields - .iter() - .map(|field| field.json_abi_str(type_engine)) - .collect::>(); - format!("({})", field_strs.join(", ")) - } - SelfType => "Self".into(), - B256 => "b256".into(), - Numeric => "u64".into(), // u64 is the default - Contract => "contract".into(), - ErrorRecovery => "unknown due to error".into(), - Enum { name, .. } => { - format!("enum {name}") - } - Struct { name, .. } => { - format!("struct {name}") - } - ContractCaller { abi_name, .. } => { - format!("contract caller {abi_name}") - } - Array(elem_ty, length) => { - format!("[{}; {}]", elem_ty.json_abi_str(type_engine), length.val()) - } - Storage { .. } => "contract storage".into(), - RawUntypedPtr => "raw untyped ptr".into(), - RawUntypedSlice => "raw untyped slice".into(), - } - } - /// maps a type to a name that is used when constructing function selectors pub(crate) fn to_selector_name( &self, diff --git a/sway-core/src/type_system/type_argument.rs b/sway-core/src/type_system/type_argument.rs index b9a25066467..6b927800f1f 100644 --- a/sway-core/src/type_system/type_argument.rs +++ b/sway-core/src/type_system/type_argument.rs @@ -60,12 +60,6 @@ impl From<&TypeParameter> for TypeArgument { } } -impl TypeArgument { - pub fn json_abi_str(&self, type_engine: &TypeEngine) -> String { - type_engine.get(self.type_id).json_abi_str(type_engine) - } -} - impl ReplaceSelfType for TypeArgument { fn replace_self_type(&mut self, engines: Engines<'_>, self_type: TypeId) { self.type_id.replace_self_type(engines, self_type); diff --git a/sway-core/src/type_system/type_parameter.rs b/sway-core/src/type_system/type_parameter.rs index 47379dbb534..626d026063c 100644 --- a/sway-core/src/type_system/type_parameter.rs +++ b/sway-core/src/type_system/type_parameter.rs @@ -10,8 +10,6 @@ use crate::{ use sway_error::error::CompileError; use sway_types::{ident::Ident, span::Span, Spanned}; -use fuel_abi_types::program_abi; - use std::{ collections::BTreeMap, fmt, @@ -158,29 +156,6 @@ impl TypeParameter { ok(type_parameter, warnings, errors) } - /// Returns the initial type ID of a TypeParameter. Also updates the provided list of types to - /// append the current TypeParameter as a `program_abi::TypeDeclaration`. - pub(crate) fn get_json_type_parameter( - &self, - type_engine: &TypeEngine, - types: &mut Vec, - ) -> usize { - let type_parameter = program_abi::TypeDeclaration { - type_id: self.initial_type_id.index(), - type_field: self - .initial_type_id - .get_json_type_str(type_engine, self.type_id), - components: self.initial_type_id.get_json_type_components( - type_engine, - types, - self.type_id, - ), - type_parameters: None, - }; - types.push(type_parameter); - self.initial_type_id.index() - } - /// Creates a [DeclMapping] from a list of [TypeParameter]s. pub(crate) fn gather_decl_mapping_from_trait_constraints( mut ctx: TypeCheckContext,