From c3104e4e60a44038634e2970e7cb0ed9270cd65f Mon Sep 17 00:00:00 2001 From: Marcos Henrich Date: Thu, 11 Jul 2024 08:36:46 +0100 Subject: [PATCH] Changed fuel_abi to return Result. Added error ABIHashCollision error. --- forc-pkg/src/pkg.rs | 11 +- forc-test/src/lib.rs | 2 +- sway-core/src/abi_generation/fuel_abi.rs | 869 ++++++++++++++--------- sway-error/src/error.rs | 8 + 4 files changed, 546 insertions(+), 344 deletions(-) diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index 60800ba4f45..e33a60cf50a 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -1837,13 +1837,15 @@ pub fn compile( let mut program_abi = match pkg.target { BuildTarget::Fuel => { let mut types = vec![]; - ProgramABI::Fuel(time_expr!( + let program_abi_res = time_expr!( "generate JSON ABI program", "generate_json_abi", fuel_abi::generate_program_abi( + &handler, &mut AbiContext { program: typed_program, abi_with_callpaths: profile.json_abi_with_callpaths, + type_ids_to_full_type_str: HashMap::::new(), }, engines, &mut types, @@ -1856,7 +1858,12 @@ pub fn compile( ), Some(sway_build_config.clone()), metrics - )) + ); + let program_abi = match program_abi_res { + Err(_) => return fail(handler), + Ok(program_abi) => program_abi, + }; + ProgramABI::Fuel(program_abi) } BuildTarget::EVM => { // Merge the ABI output of ASM gen with ABI gen to handle internal constructors diff --git a/forc-test/src/lib.rs b/forc-test/src/lib.rs index 7a2ca0a57bc..1f7337e69e2 100644 --- a/forc-test/src/lib.rs +++ b/forc-test/src/lib.rs @@ -680,7 +680,7 @@ pub fn decode_log_data( let type_lookup = program_abi .types .iter() - .map(|decl| (decl.type_id, decl.clone())) + .map(|decl| (decl.type_id.clone(), decl.clone())) .collect::>(); let logged_type_lookup: HashMap<_, _> = program_abi diff --git a/sway-core/src/abi_generation/fuel_abi.rs b/sway-core/src/abi_generation/fuel_abi.rs index 228e76fd2f3..4d4d1cd7259 100644 --- a/sway-core/src/abi_generation/fuel_abi.rs +++ b/sway-core/src/abi_generation/fuel_abi.rs @@ -1,6 +1,8 @@ use fuel_abi_types::abi::program as program_abi; use sha2::{Digest, Sha256}; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::Span; use crate::{ language::ty::{TyFunctionDecl, TyProgram, TyProgramKind}, @@ -13,6 +15,7 @@ use super::abi_str::AbiStrContext; pub struct AbiContext<'a> { pub program: &'a TyProgram, pub abi_with_callpaths: bool, + pub type_ids_to_full_type_str: HashMap, } impl<'a> AbiContext<'a> { @@ -35,37 +38,61 @@ impl<'a> AbiContext<'a> { } impl TypeId { - fn get_abi_type_id(&self, ctx: &mut AbiContext, engines: &Engines) -> String { - let string = + fn get_abi_type_id( + &self, + handler: &Handler, + ctx: &mut AbiContext, + engines: &Engines, + ) -> Result { + let type_str = self.get_abi_type_str(&ctx.to_str_context(engines, true), engines, self.clone()); let mut hasher = Sha256::new(); - hasher.update(string); + hasher.update(type_str.clone()); let result = hasher.finalize(); - format!("{:x}", result) + let type_id = format!("{:x}", result); + + if let Some(old_type_str) = ctx + .type_ids_to_full_type_str + .insert(type_id.clone(), type_str.clone()) + { + if old_type_str != type_str { + return Err( + handler.emit_err(sway_error::error::CompileError::ABIHashCollision { + span: Span::dummy(), + hash: type_id, + first_type: old_type_str, + second_type: type_str, + }), + ); + } + } + + Ok(type_id) } } pub fn generate_program_abi( + handler: &Handler, ctx: &mut AbiContext, engines: &Engines, types: &mut Vec, encoding: Option, spec_version: program_abi::Version, abi_version: program_abi::Version, -) -> program_abi::ProgramABI { +) -> Result { let decl_engine = engines.de(); - match &ctx.program.kind { + let mut program_abi = match &ctx.program.kind { TyProgramKind::Contract { abi_entries, .. } => { let functions = abi_entries .iter() .map(|x| { let fn_decl = decl_engine.get_function(x); - fn_decl.generate_abi_function(ctx, engines, types) + Ok(fn_decl.generate_abi_function(handler, ctx, engines, types)?) }) - .collect(); - let logged_types = generate_logged_types(ctx, engines, types); - let messages_types = generate_messages_types(ctx, engines, types); - let configurables = generate_configurables(ctx, engines, types); + .collect::, _>>()?; + let logged_types = generate_logged_types(handler, ctx, engines, types)?; + let messages_types = generate_messages_types(handler, ctx, engines, types)?; + let configurables = generate_configurables(handler, ctx, engines, types)?; program_abi::ProgramABI { program_type: "contract".to_string(), spec_version, @@ -80,10 +107,11 @@ pub fn generate_program_abi( } TyProgramKind::Script { main_function, .. } => { let main_function = decl_engine.get_function(main_function); - let functions = vec![main_function.generate_abi_function(ctx, engines, types)]; - let logged_types = generate_logged_types(ctx, engines, types); - let messages_types = generate_messages_types(ctx, engines, types); - let configurables = generate_configurables(ctx, engines, types); + let functions = + vec![main_function.generate_abi_function(handler, ctx, engines, types)?]; + let logged_types = generate_logged_types(handler, ctx, engines, types)?; + let messages_types = generate_messages_types(handler, ctx, engines, types)?; + let configurables = generate_configurables(handler, ctx, engines, types)?; program_abi::ProgramABI { program_type: "script".to_string(), spec_version, @@ -98,10 +126,11 @@ pub fn generate_program_abi( } TyProgramKind::Predicate { main_function, .. } => { let main_function = decl_engine.get_function(main_function); - let functions = vec![main_function.generate_abi_function(ctx, engines, types)]; - let logged_types = generate_logged_types(ctx, engines, types); - let messages_types = generate_messages_types(ctx, engines, types); - let configurables = generate_configurables(ctx, engines, types); + let functions = + vec![main_function.generate_abi_function(handler, ctx, engines, types)?]; + let logged_types = generate_logged_types(handler, ctx, engines, types)?; + let messages_types = generate_messages_types(handler, ctx, engines, types)?; + let configurables = generate_configurables(handler, ctx, engines, types)?; program_abi::ProgramABI { program_type: "predicate".to_string(), spec_version, @@ -125,80 +154,128 @@ pub fn generate_program_abi( messages_types: None, configurables: None, }, + }; + + standardize_json_abi_types(&mut program_abi); + + Ok(program_abi) +} + +/// Standardize the JSON ABI data structure by eliminating duplicate types. +fn standardize_json_abi_types(json_abi_program: &mut program_abi::ProgramABI) { + // Two `program_abi::TypeDeclaration` are deemed the same if the have the same type_id + let mut deduped_types: HashMap = + HashMap::::new(); + + // Insert values in `deduped_types` if they haven't been inserted before. Otherwise, check to see + // the types are identical if not throw an error. + for decl in &json_abi_program.types { + if let Some(ty) = deduped_types.get(&decl.type_id) { + if ty.type_field != decl.type_field + || ty.components != decl.components + || ty.type_parameters != decl.type_parameters + { + // We already throw an error on get_abi_type_id so this should not occur. + panic!("There are conflicting type ids for different type declarations.") + } + } else { + deduped_types.insert(decl.type_id.clone(), decl.clone()); + } } + + json_abi_program.types = deduped_types.values().cloned().collect::>(); + + // Sort the `program_abi::TypeDeclaration`s + json_abi_program + .types + .sort_by(|t1, t2| t1.type_field.cmp(&t2.type_field)); } fn generate_logged_types( + handler: &Handler, ctx: &mut AbiContext, engines: &Engines, types: &mut Vec, -) -> Vec { +) -> Result, ErrorEmitted> { // A list of all `program_abi::TypeDeclaration`s needed for the logged types let logged_types = ctx .program .logged_types .iter() - .map(|(_, type_id)| program_abi::TypeDeclaration { - type_id: type_id.get_abi_type_id(ctx, engines), - type_field: type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), - engines, - *type_id, - ), - components: type_id.get_abi_type_components(ctx, engines, types, *type_id), - type_parameters: type_id.get_abi_type_parameters(ctx, engines, types, *type_id), + .map(|(_, type_id)| { + Ok(program_abi::TypeDeclaration { + type_id: type_id.get_abi_type_id(handler, ctx, engines)?, + type_field: type_id.get_abi_type_str( + &ctx.to_str_context(engines, false), + engines, + *type_id, + ), + components: type_id + .get_abi_type_components(handler, ctx, engines, types, *type_id)?, + type_parameters: type_id + .get_abi_type_parameters(handler, ctx, engines, types, *type_id)?, + }) }) - .collect::>(); + .collect::, _>>()?; // Add the new types to `types` types.extend(logged_types); // Generate the JSON data for the logged types let mut log_ids: HashSet = HashSet::default(); - ctx.program + Ok(ctx + .program .logged_types .iter() - .filter_map(|(log_id, type_id)| { + .map(|(log_id, type_id)| { let log_id = log_id.hash_id; if log_ids.contains(&log_id) { - None + Ok(None) } else { log_ids.insert(log_id); - Some(program_abi::LoggedType { + Ok(Some(program_abi::LoggedType { log_id: log_id.to_string(), application: program_abi::TypeApplication { name: "".to_string(), - type_id: type_id.get_abi_type_id(ctx, engines), + type_id: type_id.get_abi_type_id(handler, ctx, engines)?, type_arguments: type_id - .get_abi_type_arguments(ctx, engines, types, *type_id), + .get_abi_type_arguments(handler, ctx, engines, types, *type_id)?, }, - }) + })) } }) - .collect() + .collect::, _>>()? + .into_iter() + .filter_map(|o| o) + .collect()) } fn generate_messages_types( + handler: &Handler, ctx: &mut AbiContext, engines: &Engines, types: &mut Vec, -) -> Vec { +) -> Result, ErrorEmitted> { // A list of all `program_abi::TypeDeclaration`s needed for the messages types let messages_types = ctx .program .messages_types .iter() - .map(|(_, type_id)| program_abi::TypeDeclaration { - type_id: type_id.get_abi_type_id(ctx, engines), - type_field: type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), - engines, - *type_id, - ), - components: type_id.get_abi_type_components(ctx, engines, types, *type_id), - type_parameters: type_id.get_abi_type_parameters(ctx, engines, types, *type_id), + .map(|(_, type_id)| { + Ok(program_abi::TypeDeclaration { + type_id: type_id.get_abi_type_id(handler, ctx, engines)?, + type_field: type_id.get_abi_type_str( + &ctx.to_str_context(engines, false), + engines, + *type_id, + ), + components: type_id + .get_abi_type_components(handler, ctx, engines, types, *type_id)?, + type_parameters: type_id + .get_abi_type_parameters(handler, ctx, engines, types, *type_id)?, + }) }) - .collect::>(); + .collect::, _>>()?; // Add the new types to `types` types.extend(messages_types); @@ -207,48 +284,59 @@ fn generate_messages_types( ctx.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.get_abi_type_id(ctx, engines), - type_arguments: type_id.get_abi_type_arguments(ctx, engines, types, *type_id), - }, + .map(|(message_id, type_id)| { + Ok(program_abi::MessageType { + message_id: **message_id as u64, + application: program_abi::TypeApplication { + name: "".to_string(), + type_id: type_id.get_abi_type_id(handler, ctx, engines)?, + type_arguments: type_id + .get_abi_type_arguments(handler, ctx, engines, types, *type_id)?, + }, + }) }) - .collect() + .collect::, _>>() } fn generate_configurables( + handler: &Handler, ctx: &mut AbiContext, engines: &Engines, types: &mut Vec, -) -> Vec { +) -> Result, ErrorEmitted> { // A list of all `program_abi::TypeDeclaration`s needed for the configurables types let configurables_types = ctx .program .configurables .iter() - .map(|decl| program_abi::TypeDeclaration { - type_id: decl.type_ascription.type_id.get_abi_type_id(ctx, engines), - type_field: decl.type_ascription.type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), - engines, - decl.type_ascription.type_id, - ), - components: decl.type_ascription.type_id.get_abi_type_components( - ctx, - engines, - types, - decl.type_ascription.type_id, - ), - type_parameters: decl.type_ascription.type_id.get_abi_type_parameters( - ctx, - engines, - types, - decl.type_ascription.type_id, - ), + .map(|decl| { + Ok(program_abi::TypeDeclaration { + type_id: decl + .type_ascription + .type_id + .get_abi_type_id(handler, ctx, engines)?, + type_field: decl.type_ascription.type_id.get_abi_type_str( + &ctx.to_str_context(engines, false), + engines, + decl.type_ascription.type_id, + ), + components: decl.type_ascription.type_id.get_abi_type_components( + handler, + ctx, + engines, + types, + decl.type_ascription.type_id, + )?, + type_parameters: decl.type_ascription.type_id.get_abi_type_parameters( + handler, + ctx, + engines, + types, + decl.type_ascription.type_id, + )?, + }) }) - .collect::>(); + .collect::, _>>()?; // Add the new types to `types` types.extend(configurables_types); @@ -257,21 +345,27 @@ fn generate_configurables( ctx.program .configurables .iter() - .map(|decl| program_abi::Configurable { - name: decl.call_path.suffix.to_string(), - application: program_abi::TypeApplication { - name: "".to_string(), - type_id: decl.type_ascription.type_id.get_abi_type_id(ctx, engines), - type_arguments: decl.type_ascription.type_id.get_abi_type_arguments( - ctx, - engines, - types, - decl.type_ascription.type_id, - ), - }, - offset: 0, + .map(|decl| { + Ok(program_abi::Configurable { + name: decl.call_path.suffix.to_string(), + application: program_abi::TypeApplication { + name: "".to_string(), + type_id: decl + .type_ascription + .type_id + .get_abi_type_id(handler, ctx, engines)?, + type_arguments: decl.type_ascription.type_id.get_abi_type_arguments( + handler, + ctx, + engines, + types, + decl.type_ascription.type_id, + )?, + }, + offset: 0, + }) }) - .collect() + .collect::, _>>() } impl TypeId { @@ -282,18 +376,22 @@ impl TypeId { /// types. pub(self) fn get_abi_type_parameters( &self, + handler: &Handler, ctx: &mut AbiContext, engines: &Engines, types: &mut Vec, resolved_type_id: TypeId, - ) -> Option> { + ) -> Result>, ErrorEmitted> { match self.is_generic_parameter(engines, resolved_type_id) { - true => None, - false => resolved_type_id.get_type_parameters(engines).map(|v| { - v.iter() - .map(|v| v.get_abi_type_parameter(ctx, engines, types)) - .collect::>() - }), + true => Ok(None), + false => resolved_type_id + .get_type_parameters(engines) + .map(|v| { + v.iter() + .map(|v| Ok(v.get_abi_type_parameter(handler, ctx, engines, types)?)) + .collect::, _>>() + }) + .map_or(Ok(None), |v| v.map(Some)), } } /// Return the components of a given (potentially generic) type while considering what it @@ -302,44 +400,52 @@ impl TypeId { /// `program_abi::TypeDeclaration`s to add the newly discovered types. pub(self) fn get_abi_type_components( &self, + handler: &Handler, ctx: &mut AbiContext, engines: &Engines, types: &mut Vec, resolved_type_id: TypeId, - ) -> Option> { + ) -> Result>, ErrorEmitted> { let type_engine = engines.te(); let decl_engine = engines.de(); - match &*type_engine.get(*self) { + Ok(match &*type_engine.get(*self) { TypeInfo::Enum(decl_ref) => { let decl = decl_engine.get_enum(decl_ref); // A list of all `program_abi::TypeDeclaration`s needed for the enum variants let variants = decl .variants .iter() - .map(|x| program_abi::TypeDeclaration { - type_id: x - .type_argument - .initial_type_id - .get_abi_type_id(ctx, engines), - type_field: x.type_argument.initial_type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), - engines, - x.type_argument.type_id, - ), - components: x.type_argument.initial_type_id.get_abi_type_components( - ctx, - engines, - types, - x.type_argument.type_id, - ), - type_parameters: x.type_argument.initial_type_id.get_abi_type_parameters( - ctx, - engines, - types, - x.type_argument.type_id, - ), + .map(|x| { + Ok(program_abi::TypeDeclaration { + type_id: x + .type_argument + .initial_type_id + .get_abi_type_id(handler, ctx, engines)?, + type_field: x.type_argument.initial_type_id.get_abi_type_str( + &ctx.to_str_context(engines, false), + engines, + x.type_argument.type_id, + ), + components: x.type_argument.initial_type_id.get_abi_type_components( + handler, + ctx, + engines, + types, + x.type_argument.type_id, + )?, + type_parameters: x + .type_argument + .initial_type_id + .get_abi_type_parameters( + handler, + ctx, + engines, + types, + x.type_argument.type_id, + )?, + }) }) - .collect::>(); + .collect::, _>>()?; types.extend(variants); // Generate the JSON data for the enum. This is basically a list of @@ -347,20 +453,26 @@ impl TypeId { Some( decl.variants .iter() - .map(|x| program_abi::TypeApplication { - name: x.name.to_string(), - type_id: x - .type_argument - .initial_type_id - .get_abi_type_id(ctx, engines), - type_arguments: x.type_argument.initial_type_id.get_abi_type_arguments( - ctx, - engines, - types, - x.type_argument.type_id, - ), + .map(|x| { + Ok(program_abi::TypeApplication { + name: x.name.to_string(), + type_id: x + .type_argument + .initial_type_id + .get_abi_type_id(handler, ctx, engines)?, + type_arguments: x + .type_argument + .initial_type_id + .get_abi_type_arguments( + handler, + ctx, + engines, + types, + x.type_argument.type_id, + )?, + }) }) - .collect(), + .collect::, _>>()?, ) } TypeInfo::Struct(decl_ref) => { @@ -370,30 +482,37 @@ impl TypeId { let field_types = decl .fields .iter() - .map(|x| program_abi::TypeDeclaration { - type_id: x - .type_argument - .initial_type_id - .get_abi_type_id(ctx, engines), - type_field: x.type_argument.initial_type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), - engines, - x.type_argument.type_id, - ), - components: x.type_argument.initial_type_id.get_abi_type_components( - ctx, - engines, - types, - x.type_argument.type_id, - ), - type_parameters: x.type_argument.initial_type_id.get_abi_type_parameters( - ctx, - engines, - types, - x.type_argument.type_id, - ), + .map(|x| { + Ok(program_abi::TypeDeclaration { + type_id: x + .type_argument + .initial_type_id + .get_abi_type_id(handler, ctx, engines)?, + type_field: x.type_argument.initial_type_id.get_abi_type_str( + &ctx.to_str_context(engines, false), + engines, + x.type_argument.type_id, + ), + components: x.type_argument.initial_type_id.get_abi_type_components( + handler, + ctx, + engines, + types, + x.type_argument.type_id, + )?, + type_parameters: x + .type_argument + .initial_type_id + .get_abi_type_parameters( + handler, + ctx, + engines, + types, + x.type_argument.type_id, + )?, + }) }) - .collect::>(); + .collect::, _>>()?; types.extend(field_types); // Generate the JSON data for the struct. This is basically a list of @@ -401,44 +520,54 @@ impl TypeId { Some( decl.fields .iter() - .map(|x| program_abi::TypeApplication { - name: x.name.to_string(), - type_id: x - .type_argument - .initial_type_id - .get_abi_type_id(ctx, engines), - type_arguments: x.type_argument.initial_type_id.get_abi_type_arguments( - ctx, - engines, - types, - x.type_argument.type_id, - ), + .map(|x| { + Ok(program_abi::TypeApplication { + name: x.name.to_string(), + type_id: x + .type_argument + .initial_type_id + .get_abi_type_id(handler, ctx, engines)?, + type_arguments: x + .type_argument + .initial_type_id + .get_abi_type_arguments( + handler, + ctx, + engines, + types, + x.type_argument.type_id, + )?, + }) }) - .collect(), + .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_abi_ty = program_abi::TypeDeclaration { - type_id: elem_ty.initial_type_id.get_abi_type_id(ctx, engines), + type_id: elem_ty + .initial_type_id + .get_abi_type_id(handler, ctx, engines)?, type_field: elem_ty.initial_type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, elem_ty.type_id, ), components: elem_ty.initial_type_id.get_abi_type_components( + handler, ctx, engines, types, elem_ty.type_id, - ), + )?, type_parameters: elem_ty.initial_type_id.get_abi_type_parameters( + handler, ctx, engines, types, elem_ty.type_id, - ), + )?, }; types.push(elem_abi_ty); @@ -446,13 +575,16 @@ impl TypeId { // `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.get_abi_type_id(ctx, engines), + type_id: elem_ty + .initial_type_id + .get_abi_type_id(handler, ctx, engines)?, type_arguments: elem_ty.initial_type_id.get_abi_type_arguments( + handler, ctx, engines, types, elem_ty.type_id, - ), + )?, }]) } else { unreachable!(); @@ -463,21 +595,25 @@ impl TypeId { // 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.get_abi_type_id(ctx, engines), - type_field: x.initial_type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), - engines, - x.type_id, - ), - components: x - .initial_type_id - .get_abi_type_components(ctx, engines, types, x.type_id), - type_parameters: x - .initial_type_id - .get_abi_type_parameters(ctx, engines, types, x.type_id), + .map(|x| { + Ok(program_abi::TypeDeclaration { + type_id: x + .initial_type_id + .get_abi_type_id(handler, ctx, engines)?, + type_field: x.initial_type_id.get_abi_type_str( + &ctx.to_str_context(engines, false), + engines, + x.type_id, + ), + components: x.initial_type_id.get_abi_type_components( + handler, ctx, engines, types, x.type_id, + )?, + type_parameters: x.initial_type_id.get_abi_type_parameters( + handler, ctx, engines, types, x.type_id, + )?, + }) }) - .collect::>(); + .collect::, _>>()?; types.extend(fields_types); @@ -486,14 +622,18 @@ impl TypeId { Some( fields .iter() - .map(|x| program_abi::TypeApplication { - name: "__tuple_element".to_string(), - type_id: x.initial_type_id.get_abi_type_id(ctx, engines), - type_arguments: x - .initial_type_id - .get_abi_type_arguments(ctx, engines, types, x.type_id), + .map(|x| { + Ok(program_abi::TypeApplication { + name: "__tuple_element".to_string(), + type_id: x + .initial_type_id + .get_abi_type_id(handler, ctx, engines)?, + type_arguments: x.initial_type_id.get_abi_type_arguments( + handler, ctx, engines, types, x.type_id, + )?, + }) }) - .collect(), + .collect::, _>>()?, ) } else { unreachable!() @@ -512,24 +652,34 @@ impl TypeId { .unwrap_or_default() .iter(), ) - .map(|(v, p)| program_abi::TypeDeclaration { - type_id: v.initial_type_id.get_abi_type_id(ctx, engines), - type_field: v.initial_type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), - engines, - p.type_id, - ), - components: v - .initial_type_id - .get_abi_type_components(ctx, engines, types, p.type_id), - type_parameters: v - .initial_type_id - .get_abi_type_parameters(ctx, engines, types, p.type_id), + .map(|(v, p)| { + Ok(program_abi::TypeDeclaration { + type_id: v + .initial_type_id + .get_abi_type_id(handler, ctx, engines)?, + type_field: v.initial_type_id.get_abi_type_str( + &ctx.to_str_context(engines, false), + engines, + p.type_id, + ), + components: v.initial_type_id.get_abi_type_components( + handler, ctx, engines, types, p.type_id, + )?, + type_parameters: v.initial_type_id.get_abi_type_parameters( + handler, ctx, engines, types, p.type_id, + )?, + }) }) - .collect::>(); + .collect::, _>>()?; types.extend(type_args); - resolved_type_id.get_abi_type_components(ctx, engines, types, resolved_type_id) + resolved_type_id.get_abi_type_components( + handler, + ctx, + engines, + types, + resolved_type_id, + )? } else { None } @@ -537,7 +687,7 @@ impl TypeId { TypeInfo::Alias { .. } => { if let TypeInfo::Alias { ty, .. } = &*type_engine.get(resolved_type_id) { ty.initial_type_id - .get_abi_type_components(ctx, engines, types, ty.type_id) + .get_abi_type_components(handler, ctx, engines, types, ty.type_id)? } else { None } @@ -547,11 +697,17 @@ impl TypeId { if *self == resolved_type_id { None } else { - resolved_type_id.get_abi_type_components(ctx, engines, types, resolved_type_id) + resolved_type_id.get_abi_type_components( + handler, + ctx, + engines, + types, + resolved_type_id, + )? } } _ => None, - } + }) } /// Return the type arguments of a given (potentially generic) type while considering what it @@ -560,15 +716,16 @@ impl TypeId { /// `program_abi::TypeDeclaration`s to add the newly discovered types. pub(self) fn get_abi_type_arguments( &self, + handler: &Handler, ctx: &mut AbiContext, engines: &Engines, types: &mut Vec, resolved_type_id: TypeId, - ) -> Option> { + ) -> Result>, ErrorEmitted> { let type_engine = engines.te(); let decl_engine = engines.de(); let resolved_params = resolved_type_id.get_type_parameters(engines); - match &*type_engine.get(*self) { + Ok(match &*type_engine.get(*self) { TypeInfo::Custom { type_arguments: Some(type_arguments), .. @@ -577,36 +734,41 @@ impl TypeId { let abi_type_arguments = type_arguments .iter() .zip(resolved_params.iter()) - .map(|(v, p)| program_abi::TypeDeclaration { - type_id: v.initial_type_id.get_abi_type_id(ctx, engines), - type_field: v.initial_type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), - engines, - p.type_id, - ), - components: v - .initial_type_id - .get_abi_type_components(ctx, engines, types, p.type_id), - type_parameters: v - .initial_type_id - .get_abi_type_parameters(ctx, engines, types, p.type_id), + .map(|(v, p)| { + Ok(program_abi::TypeDeclaration { + type_id: v.initial_type_id.get_abi_type_id(handler, ctx, engines)?, + type_field: v.initial_type_id.get_abi_type_str( + &ctx.to_str_context(engines, false), + engines, + p.type_id, + ), + components: v + .initial_type_id + .get_abi_type_components(handler, ctx, engines, types, p.type_id)?, + type_parameters: v + .initial_type_id + .get_abi_type_parameters(handler, ctx, engines, types, p.type_id)?, + }) }) - .collect::>(); + .collect::, _>>()?; types.extend(abi_type_arguments); type_arguments .iter() - .map(|arg| program_abi::TypeApplication { - name: "".to_string(), - type_id: arg.initial_type_id.get_abi_type_id(ctx, engines), - type_arguments: arg.initial_type_id.get_abi_type_arguments( - ctx, - engines, - types, - arg.type_id, - ), + .map(|arg| { + Ok(program_abi::TypeApplication { + name: "".to_string(), + type_id: arg.initial_type_id.get_abi_type_id(handler, ctx, engines)?, + type_arguments: arg.initial_type_id.get_abi_type_arguments( + handler, + ctx, + engines, + types, + arg.type_id, + )?, + }) }) - .collect::>() + .collect::, _>>()? }), TypeInfo::Enum(decl_ref) => { let decl = decl_engine.get_enum(decl_ref); @@ -614,37 +776,42 @@ impl TypeId { let abi_type_arguments = decl .type_parameters .iter() - .map(|v| program_abi::TypeDeclaration { - type_id: v.type_id.get_abi_type_id(ctx, engines), - type_field: v.type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), - engines, - v.type_id, - ), - components: v - .type_id - .get_abi_type_components(ctx, engines, types, v.type_id), - type_parameters: v - .type_id - .get_abi_type_parameters(ctx, engines, types, v.type_id), + .map(|v| { + Ok(program_abi::TypeDeclaration { + type_id: v.type_id.get_abi_type_id(handler, ctx, engines)?, + type_field: v.type_id.get_abi_type_str( + &ctx.to_str_context(engines, false), + engines, + v.type_id, + ), + components: v + .type_id + .get_abi_type_components(handler, ctx, engines, types, v.type_id)?, + type_parameters: v + .type_id + .get_abi_type_parameters(handler, ctx, engines, types, v.type_id)?, + }) }) - .collect::>(); + .collect::, _>>()?; types.extend(abi_type_arguments); Some( decl.type_parameters .iter() - .map(|arg| program_abi::TypeApplication { - name: "".to_string(), - type_id: arg.type_id.get_abi_type_id(ctx, engines), - type_arguments: arg.type_id.get_abi_type_arguments( - ctx, - engines, - types, - arg.type_id, - ), + .map(|arg| { + Ok(program_abi::TypeApplication { + name: "".to_string(), + type_id: arg.type_id.get_abi_type_id(handler, ctx, engines)?, + type_arguments: arg.type_id.get_abi_type_arguments( + handler, + ctx, + engines, + types, + arg.type_id, + )?, + }) }) - .collect::>(), + .collect::, _>>()?, ) } @@ -654,103 +821,115 @@ impl TypeId { let abi_type_arguments = decl .type_parameters .iter() - .map(|v| program_abi::TypeDeclaration { - type_id: v.type_id.get_abi_type_id(ctx, engines), - type_field: v.type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), - engines, - v.type_id, - ), - components: v - .type_id - .get_abi_type_components(ctx, engines, types, v.type_id), - type_parameters: v - .type_id - .get_abi_type_parameters(ctx, engines, types, v.type_id), + .map(|v| { + Ok(program_abi::TypeDeclaration { + type_id: v.type_id.get_abi_type_id(handler, ctx, engines)?, + type_field: v.type_id.get_abi_type_str( + &ctx.to_str_context(engines, false), + engines, + v.type_id, + ), + components: v + .type_id + .get_abi_type_components(handler, ctx, engines, types, v.type_id)?, + type_parameters: v + .type_id + .get_abi_type_parameters(handler, ctx, engines, types, v.type_id)?, + }) }) - .collect::>(); + .collect::, _>>()?; types.extend(abi_type_arguments); Some( decl.type_parameters .iter() - .map(|arg| program_abi::TypeApplication { - name: "".to_string(), - type_id: arg.type_id.get_abi_type_id(ctx, engines), - type_arguments: arg.type_id.get_abi_type_arguments( - ctx, - engines, - types, - arg.type_id, - ), + .map(|arg| { + Ok(program_abi::TypeApplication { + name: "".to_string(), + type_id: arg.type_id.get_abi_type_id(handler, ctx, engines)?, + type_arguments: arg.type_id.get_abi_type_arguments( + handler, + ctx, + engines, + types, + arg.type_id, + )?, + }) }) - .collect::>(), + .collect::, _>>()?, ) } _ => None, - } + }) } } impl TyFunctionDecl { pub(self) fn generate_abi_function( &self, + handler: &Handler, ctx: &mut AbiContext, engines: &Engines, types: &mut Vec, - ) -> program_abi::ABIFunction { + ) -> Result { // 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 - .type_argument - .initial_type_id - .get_abi_type_id(ctx, engines), - type_field: x.type_argument.initial_type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), - engines, - x.type_argument.type_id, - ), - components: x.type_argument.initial_type_id.get_abi_type_components( - ctx, - engines, - types, - x.type_argument.type_id, - ), - type_parameters: x.type_argument.type_id.get_abi_type_parameters( - ctx, - engines, - types, - x.type_argument.type_id, - ), + .map(|x| { + Ok(program_abi::TypeDeclaration { + type_id: x + .type_argument + .initial_type_id + .get_abi_type_id(handler, ctx, engines)?, + type_field: x.type_argument.initial_type_id.get_abi_type_str( + &ctx.to_str_context(engines, false), + engines, + x.type_argument.type_id, + ), + components: x.type_argument.initial_type_id.get_abi_type_components( + handler, + ctx, + engines, + types, + x.type_argument.type_id, + )?, + type_parameters: x.type_argument.type_id.get_abi_type_parameters( + handler, + ctx, + engines, + types, + x.type_argument.type_id, + )?, + }) }) - .collect::>(); + .collect::, _>>()?; // The single `program_abi::TypeDeclaration` needed for the output let output_type = program_abi::TypeDeclaration { type_id: self .return_type .initial_type_id - .get_abi_type_id(ctx, engines), + .get_abi_type_id(handler, ctx, engines)?, type_field: self.return_type.initial_type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, self.return_type.type_id, ), components: self.return_type.type_id.get_abi_type_components( + handler, ctx, engines, types, self.return_type.type_id, - ), + )?, type_parameters: self.return_type.type_id.get_abi_type_parameters( + handler, ctx, engines, types, self.return_type.type_id, - ), + )?, }; // Add the new types to `types` @@ -758,40 +937,44 @@ impl TyFunctionDecl { types.push(output_type); // Generate the JSON data for the function - program_abi::ABIFunction { + Ok(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 - .type_argument - .initial_type_id - .get_abi_type_id(ctx, engines), - type_arguments: x.type_argument.initial_type_id.get_abi_type_arguments( - ctx, - engines, - types, - x.type_argument.type_id, - ), + .map(|x| { + Ok(program_abi::TypeApplication { + name: x.name.to_string(), + type_id: x + .type_argument + .initial_type_id + .get_abi_type_id(handler, ctx, engines)?, + type_arguments: x.type_argument.initial_type_id.get_abi_type_arguments( + handler, + ctx, + engines, + types, + x.type_argument.type_id, + )?, + }) }) - .collect(), + .collect::, _>>()?, output: program_abi::TypeApplication { name: "".to_string(), type_id: self .return_type .initial_type_id - .get_abi_type_id(ctx, engines), + .get_abi_type_id(handler, ctx, engines)?, type_arguments: self.return_type.initial_type_id.get_abi_type_arguments( + handler, ctx, engines, types, self.return_type.type_id, - ), + )?, }, attributes: generate_attributes_map(&self.attributes), - } + }) } } @@ -818,11 +1001,14 @@ impl TypeParameter { /// append the current TypeParameter as a `program_abi::TypeDeclaration`. pub(self) fn get_abi_type_parameter( &self, + handler: &Handler, ctx: &mut AbiContext, engines: &Engines, types: &mut Vec, - ) -> String { - let type_id = self.initial_type_id.get_abi_type_id(ctx, engines); + ) -> Result { + let type_id = self + .initial_type_id + .get_abi_type_id(handler, ctx, engines)?; let type_parameter = program_abi::TypeDeclaration { type_id: type_id.clone(), type_field: self.initial_type_id.get_abi_type_str( @@ -831,14 +1017,15 @@ impl TypeParameter { self.type_id, ), components: self.initial_type_id.get_abi_type_components( + handler, ctx, engines, types, self.type_id, - ), + )?, type_parameters: None, }; types.push(type_parameter); - type_id + Ok(type_id) } } diff --git a/sway-error/src/error.rs b/sway-error/src/error.rs index a2bec9fc219..73c6651c626 100644 --- a/sway-error/src/error.rs +++ b/sway-error/src/error.rs @@ -966,6 +966,13 @@ pub enum CompileError { EncodingUnsupportedType { span: Span }, #[error("Configurables need a function named \"abi_decode_in_place\" to be in scope.")] ConfigurableMissingAbiDecodeInPlace { span: Span }, + #[error("Collision detected between two different types.\n Shared hash:{hash}\n First type:{first_type}\n Second type:{second_type}")] + ABIHashCollision { + span: Span, + hash: String, + first_type: String, + second_type: String, + }, } impl std::convert::From for CompileError { @@ -1178,6 +1185,7 @@ impl Spanned for CompileError { CannotBeEvaluatedToConfigurableSizeUnknown { span } => span.clone(), EncodingUnsupportedType { span } => span.clone(), ConfigurableMissingAbiDecodeInPlace { span } => span.clone(), + ABIHashCollision { span, .. } => span.clone(), } } }