From 69e815413734e4265808863f5f0f0fb2447b0864 Mon Sep 17 00:00:00 2001 From: IGI-111 Date: Wed, 19 Jul 2023 04:35:33 +0200 Subject: [PATCH] Numeric type inference This does two things. 1. Integer types no longer automatically cast to each other. Methods such as `as_u64` and `try_as_u8` have been introduced to require the user to explicit the cast. Warnings about casts losing precision have been removed as they are no longer possible. 2. Numeric literals (such as `32` without further qualifications) no longer immediately decay to a `u64` and we instead attempt to type them as `TypeInfo::Numeric` as far as possible to allow their usage with any integer type. Numeric intrinsics unify arguments with the numeric type to enforce their constraints. Numeric values are forced to decay to `u64` when resolving methods or traits. This change is a prerequisite to move our representation of sub-byte-sized values to a different memory representation, as numeric types need to be distinct if we are ever to treat them differently. --- sway-core/src/asm_generation/from_ir.rs | 23 +- sway-core/src/ir_generation/const_eval.rs | 13 +- .../ast_node/expression/intrinsic_function.rs | 224 ++++-------------- .../ast_node/expression/typed_expression.rs | 11 +- .../src/semantic_analysis/coins_analysis.rs | 1 + .../semantic_analysis/namespace/namespace.rs | 19 +- .../semantic_analysis/namespace/trait_map.rs | 10 +- .../to_parsed_lang/convert_parse_tree.rs | 4 +- sway-core/src/type_system/engine.rs | 145 ++++++++++++ sway-core/src/type_system/id.rs | 12 +- sway-core/src/type_system/info.rs | 5 +- sway-core/src/type_system/unify/unifier.rs | 65 +---- .../src/type_system/unify/unify_check.rs | 16 +- sway-error/src/warning.rs | 12 +- sway-ir/src/error.rs | 6 +- sway-ir/src/irtype.rs | 6 - sway-ir/src/verify.rs | 2 + sway-lib-core/src/primitive_conversions.sw | 42 +++- sway-lib-core/src/primitives.sw | 8 +- sway-lib-std/src/auth.sw | 4 +- sway-lib-std/src/inputs.sw | 5 +- sway-lib-std/src/lib.sw | 1 + sway-lib-std/src/prelude.sw | 3 + sway-lib-std/src/primitive_conversions.sw | 70 ++++++ .../fixtures/tokens/consts/src/more_consts.sw | 2 +- .../abort_control_flow_bad/test.toml | 2 +- .../should_fail/binop_intrinsics/src/main.sw | 4 + .../should_fail/binop_intrinsics/test.toml | 57 ++++- .../should_fail/eq_intrinsic/src/main.sw | 1 + .../should_fail/eq_intrinsic/test.toml | 10 +- .../match_expressions_wrong_struct/test.toml | 4 +- .../where_clause_impls/src/main.sw | 4 +- .../test.toml | 2 +- .../src/main.sw | 2 +- .../src/main.sw | 2 +- .../language/binop_intrinsics/src/main.sw | 1 + .../fix_opcode_bug/json_abi_oracle.json | 2 +- .../language/fix_opcode_bug/src/main.sw | 2 +- .../language/generic_functions/src/main.sw | 2 +- .../language/generic_impl_self/src/main.sw | 6 +- .../language/generic_traits/src/main.sw | 74 +++--- .../language/integer_type_inference/Forc.lock | 10 + .../language/integer_type_inference/Forc.toml | 3 + .../integer_type_inference/src/main.sw | 68 ++---- .../language/numeric_constants/src/main.sw | 11 +- .../tuple_access/json_abi_oracle.json | 2 +- .../language/tuple_access/src/main.sw | 2 +- .../use_full_path_names/json_abi_oracle.json | 2 +- .../language/use_full_path_names/src/main.sw | 2 +- .../should_pass/stdlib/vec/src/main.sw | 2 +- .../test_contracts/issue_1512_repro/Forc.lock | 8 + .../test_contracts/issue_1512_repro/Forc.toml | 1 + .../issue_1512_repro/src/main.sw | 34 +-- .../test_artifacts/tx_contract/src/main.sw | 4 +- .../test_projects/generics_in_abi/src/main.sw | 4 +- .../test_projects/token_ops/src/main.sw | 6 +- 56 files changed, 580 insertions(+), 463 deletions(-) create mode 100644 sway-lib-std/src/primitive_conversions.sw diff --git a/sway-core/src/asm_generation/from_ir.rs b/sway-core/src/asm_generation/from_ir.rs index 95df6d0f597..b8ec8d3326f 100644 --- a/sway-core/src/asm_generation/from_ir.rs +++ b/sway-core/src/asm_generation/from_ir.rs @@ -200,28 +200,7 @@ pub enum StateAccessType { } pub(crate) fn ir_type_size_in_bytes(context: &Context, ty: &Type) -> u64 { - match ty.get_content(context) { - TypeContent::Unit | TypeContent::Bool | TypeContent::Uint(_) | TypeContent::Pointer(_) => 8, - TypeContent::Slice => 16, - TypeContent::B256 => 32, - TypeContent::String(n) => size_bytes_round_up_to_word_alignment!(*n), - TypeContent::Array(el_ty, cnt) => cnt * ir_type_size_in_bytes(context, el_ty), - TypeContent::Struct(field_tys) => { - // Sum up all the field sizes. - field_tys - .iter() - .map(|field_ty| ir_type_size_in_bytes(context, field_ty)) - .sum() - } - TypeContent::Union(field_tys) => { - // Find the max size for field sizes. - field_tys - .iter() - .map(|field_ty| ir_type_size_in_bytes(context, field_ty)) - .max() - .unwrap_or(0) - } - } + ty.size_in_bytes(context) } pub(crate) fn ir_type_str_size_in_bytes(context: &Context, ty: &Type) -> u64 { diff --git a/sway-core/src/ir_generation/const_eval.rs b/sway-core/src/ir_generation/const_eval.rs index c976071774c..66e908a02ad 100644 --- a/sway-core/src/ir_generation/const_eval.rs +++ b/sway-core/src/ir_generation/const_eval.rs @@ -9,6 +9,7 @@ use crate::{ }, metadata::MetadataManager, semantic_analysis::*, + UnifyCheck, }; use super::{ @@ -424,14 +425,10 @@ fn const_eval_typed_expr( let te = lookup.engines.te(); assert!({ - let elem_type_info = te.get(*elem_type); - element_typs.iter().all(|tid| { - lookup - .engines - .te() - .get(*tid) - .eq(&elem_type_info, lookup.engines) - }) + let unify_check = UnifyCheck::coercion(lookup.engines); + element_typs + .iter() + .all(|tid| unify_check.check(*tid, *elem_type)) }); create_array_aggregate( diff --git a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs index d3a9933e148..77c73e5a836 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs @@ -101,9 +101,9 @@ fn type_check_not( return err(warnings, errors); } - let mut ctx = ctx - .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + let return_type = type_engine.insert(engines, TypeInfo::Numeric); + + let mut ctx = ctx.with_help_text("").with_type_annotation(return_type); let operand = arguments[0].clone(); let operand_expr = check!( @@ -113,26 +113,6 @@ fn type_check_not( errors ); - let operand_typeinfo = check!( - CompileResult::from( - type_engine - .to_typeinfo(operand_expr.return_type, &operand_expr.span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); - let is_valid_arg_ty = matches!(operand_typeinfo, TypeInfo::UnsignedInteger(_)); - if !is_valid_arg_ty { - errors.push(CompileError::IntrinsicUnsupportedArgType { - name: kind.to_string(), - span: operand_expr.span, - hint: Hint::empty(), - }); - return err(warnings, errors); - } - ok( ( ty::TyIntrinsicFunctionKind { @@ -141,7 +121,7 @@ fn type_check_not( type_arguments: vec![], span, }, - type_engine.insert(engines, operand_typeinfo), + return_type, ), warnings, errors, @@ -362,6 +342,13 @@ fn type_check_cmp( warnings, errors ); + let rhs = arguments[1].clone(); + let rhs = check!( + ty::TyExpression::type_check(ctx, rhs), + return err(warnings, errors), + warnings, + errors + ); // Check for supported argument types let arg_ty = check!( @@ -374,7 +361,7 @@ fn type_check_cmp( warnings, errors ); - let is_valid_arg_ty = matches!(arg_ty, TypeInfo::UnsignedInteger(_)) + let is_valid_arg_ty = matches!(arg_ty, TypeInfo::UnsignedInteger(_) | TypeInfo::Numeric) || (matches!(&kind, Intrinsic::Eq) && matches!(arg_ty, TypeInfo::Boolean | TypeInfo::RawUntypedPtr)); if !is_valid_arg_ty { @@ -386,17 +373,6 @@ fn type_check_cmp( return err(warnings, errors); } - let rhs = arguments[1].clone(); - let ctx = ctx - .by_ref() - .with_help_text("Incorrect argument type") - .with_type_annotation(lhs.return_type); - let rhs = check!( - ty::TyExpression::type_check(ctx, rhs), - return err(warnings, errors), - warnings, - errors - ); ok( ( ty::TyIntrinsicFunctionKind { @@ -450,9 +426,9 @@ fn type_check_gtf( } // Type check the first argument which is the index - let mut ctx = ctx - .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + let mut ctx = ctx.by_ref().with_type_annotation( + type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), + ); let index = check!( ty::TyExpression::type_check(ctx.by_ref(), arguments[0].clone()), return err(warnings, errors), @@ -461,9 +437,9 @@ fn type_check_gtf( ); // Type check the second argument which is the tx field ID - let mut ctx = ctx - .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + let mut ctx = ctx.by_ref().with_type_annotation( + type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), + ); let tx_field_id = check!( ty::TyExpression::type_check(ctx.by_ref(), arguments[1].clone()), return err(warnings, errors), @@ -471,50 +447,6 @@ fn type_check_gtf( errors ); - // Make sure that the index argument is a `u64` - let index_type_info = check!( - CompileResult::from( - type_engine - .to_typeinfo(index.return_type, &index.span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); - if !matches!( - index_type_info, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour) - ) { - errors.push(CompileError::IntrinsicUnsupportedArgType { - name: kind.to_string(), - span: index.span.clone(), - hint: Hint::empty(), - }); - } - - // Make sure that the tx field ID is a `u64` - let tx_field_type_info = check!( - CompileResult::from( - type_engine - .to_typeinfo(tx_field_id.return_type, &tx_field_id.span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); - if !matches!( - tx_field_type_info, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour) - ) { - errors.push(CompileError::IntrinsicUnsupportedArgType { - name: kind.to_string(), - span: tx_field_id.span.clone(), - hint: Hint::empty(), - }); - } - let targ = type_arguments[0].clone(); let initial_type_info = check!( CompileResult::from( @@ -1084,9 +1016,11 @@ fn type_check_binary_op( return err(warnings, errors); } + let return_type = type_engine.insert(engines, TypeInfo::Numeric); let mut ctx = ctx .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(return_type) + .with_help_text("Incorrect argument type"); let lhs = arguments[0].clone(); let lhs = check!( @@ -1095,39 +1029,14 @@ fn type_check_binary_op( warnings, errors ); - - // Check for supported argument types - let arg_ty = check!( - CompileResult::from( - type_engine - .to_typeinfo(lhs.return_type, &lhs.span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); - let is_valid_arg_ty = matches!(arg_ty, TypeInfo::UnsignedInteger(_)); - if !is_valid_arg_ty { - errors.push(CompileError::IntrinsicUnsupportedArgType { - name: kind.to_string(), - span: lhs.span, - hint: Hint::empty(), - }); - return err(warnings, errors); - } - let rhs = arguments[1].clone(); - let ctx = ctx - .by_ref() - .with_help_text("Incorrect argument type") - .with_type_annotation(lhs.return_type); let rhs = check!( ty::TyExpression::type_check(ctx, rhs), return err(warnings, errors), warnings, errors ); + ok( ( ty::TyIntrinsicFunctionKind { @@ -1136,7 +1045,7 @@ fn type_check_binary_op( type_arguments: vec![], span, }, - type_engine.insert(engines, arg_ty), + return_type, ), warnings, errors, @@ -1180,71 +1089,32 @@ fn type_check_shift_binary_op( return err(warnings, errors); } - let mut ctx = ctx - .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + let return_type = type_engine.insert(engines, TypeInfo::Numeric); let lhs = arguments[0].clone(); let lhs = check!( - ty::TyExpression::type_check(ctx.by_ref(), lhs), - return err(warnings, errors), - warnings, - errors - ); - - // Check for supported argument types - let arg_ty = check!( - CompileResult::from( - type_engine - .to_typeinfo(lhs.return_type, &lhs.span) - .map_err(CompileError::from) + ty::TyExpression::type_check( + ctx.by_ref() + .with_help_text("Incorrect argument type") + .with_type_annotation(return_type), + lhs ), - TypeInfo::ErrorRecovery, + return err(warnings, errors), warnings, errors ); - let is_valid_arg_ty = matches!(arg_ty, TypeInfo::UnsignedInteger(_)); - if !is_valid_arg_ty { - errors.push(CompileError::IntrinsicUnsupportedArgType { - name: kind.to_string(), - span: lhs.span, - hint: Hint::empty(), - }); - return err(warnings, errors); - } - - let ctx = ctx - .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let rhs = arguments[1].clone(); let rhs = check!( - ty::TyExpression::type_check(ctx, rhs), - return err(warnings, errors), - warnings, - errors - ); - - // Check for supported argument types - let rhs_ty = check!( - CompileResult::from( - type_engine - .to_typeinfo(rhs.return_type, &rhs.span) - .map_err(CompileError::from) + ty::TyExpression::type_check( + ctx.by_ref() + .with_help_text("Incorrect argument type") + .with_type_annotation(engines.te().insert(engines, TypeInfo::Numeric)), + rhs ), - TypeInfo::ErrorRecovery, + return err(warnings, errors), warnings, errors ); - let is_valid_rhs_ty = matches!(rhs_ty, TypeInfo::UnsignedInteger(_)); - if !is_valid_rhs_ty { - errors.push(CompileError::IntrinsicUnsupportedArgType { - name: kind.to_string(), - span: lhs.span, - hint: Hint::empty(), - }); - return err(warnings, errors); - } ok( ( @@ -1254,7 +1124,7 @@ fn type_check_shift_binary_op( type_arguments: vec![], span, }, - type_engine.insert(engines, arg_ty), + return_type, ), warnings, errors, @@ -1296,9 +1166,9 @@ fn type_check_revert( } // Type check the argument which is the revert code - let mut ctx = ctx - .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + let mut ctx = ctx.by_ref().with_type_annotation( + type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), + ); let revert_code = check!( ty::TyExpression::type_check(ctx.by_ref(), arguments[0].clone()), return err(warnings, errors), @@ -1306,20 +1176,6 @@ fn type_check_revert( errors ); - // Make sure that the revert code is a `u64` - if !matches!( - type_engine - .to_typeinfo(revert_code.return_type, &revert_code.span) - .unwrap(), - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour) - ) { - errors.push(CompileError::IntrinsicUnsupportedArgType { - name: kind.to_string(), - span: revert_code.span.clone(), - hint: Hint::empty(), - }); - } - ok( ( ty::TyIntrinsicFunctionKind { diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 5529d48aece..2b5d7ff7262 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -2016,15 +2016,10 @@ impl ty::TyExpression { ), }, TypeInfo::Numeric => ( - num.to_string().parse().map(Literal::U64).map_err(|e| { - Literal::handle_parse_int_error( - engines, - e, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - span.clone(), - ) + num.to_string().parse().map(Literal::Numeric).map_err(|e| { + Literal::handle_parse_int_error(engines, e, TypeInfo::Numeric, span.clone()) }), - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), + type_engine.insert(engines, TypeInfo::Numeric), ), _ => unreachable!("Unexpected type for integer literals"), }, diff --git a/sway-core/src/semantic_analysis/coins_analysis.rs b/sway-core/src/semantic_analysis/coins_analysis.rs index 1e6d4123d11..d5df49cb5a3 100644 --- a/sway-core/src/semantic_analysis/coins_analysis.rs +++ b/sway-core/src/semantic_analysis/coins_analysis.rs @@ -12,6 +12,7 @@ pub fn possibly_nonzero_u64_expression( use ty::TyExpressionVariant::*; match &expr.expression { Literal(crate::language::Literal::U64(value)) => *value != 0, + Literal(crate::language::Literal::Numeric(value)) => *value != 0, // not a u64 literal, hence we return true to be on the safe side Literal(_) => true, ConstantExpression { const_decl, .. } => match &const_decl.value { diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index 63e8d6b415b..9cbffd967b1 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -264,7 +264,18 @@ impl Namespace { let decl_engine = engines.de(); let type_engine = engines.te(); - let unify_check = UnifyCheck::non_dynamic_equality(engines); + let eq_check = UnifyCheck::non_dynamic_equality(engines); + let coercion_check = UnifyCheck::coercion(engines); + + // default numeric types to u64 + if type_engine.contains_numeric(decl_engine, type_id) { + check!( + type_engine.decay_numeric(engines, type_id, &method_name.span()), + return err(warnings, errors), + warnings, + errors + ); + } let matching_item_decl_refs = check!( self.find_items_for_type(type_id, method_prefix, method_name, self_type, engines,), @@ -294,9 +305,9 @@ impl Namespace { .parameters .iter() .zip(args_buf.iter()) - .all(|(p, a)| unify_check.check(p.type_argument.type_id, a.return_type)) + .all(|(p, a)| coercion_check.check(p.type_argument.type_id, a.return_type)) && (matches!(type_engine.get(annotation_type), TypeInfo::Unknown) - || unify_check.check(annotation_type, method.return_type.type_id)) + || coercion_check.check(annotation_type, method.return_type.type_id)) { maybe_method_decl_refs.push(decl_ref); } @@ -346,7 +357,7 @@ impl Namespace { warnings, errors ); - if !unify_check.check(p1_type_id, p2_type_id) { + if !eq_check.check(p1_type_id, p2_type_id) { params_equal = false; break; } diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index e43435eceee..1d1dcf37daf 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -860,13 +860,21 @@ impl TraitMap { access_span: &Span, engines: &Engines, ) -> CompileResult<()> { - let warnings = vec![]; + let mut warnings = vec![]; let mut errors = vec![]; let type_engine = engines.te(); let _decl_engine = engines.de(); let unify_check = UnifyCheck::non_dynamic_equality(engines); + // resolving trait constraits require a concrete type, we need to default numeric to u64 + check!( + type_engine.decay_numeric(engines, type_id, access_span), + return err(warnings, errors), + warnings, + errors + ); + let all_impld_traits: BTreeMap = self .trait_impls .iter() diff --git a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs index 71e65b48229..00f96eab05e 100644 --- a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs +++ b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs @@ -2809,7 +2809,7 @@ fn literal_to_literal( if let Some(hex_digits) = orig_str.strip_prefix("0x") { let num_digits = hex_digits.chars().filter(|c| *c != '_').count(); match num_digits { - 1..=16 => Literal::U64(u64::try_from(parsed).unwrap()), + 1..=16 => Literal::Numeric(u64::try_from(parsed).unwrap()), 64 => { let bytes = parsed.to_bytes_be(); let mut full_bytes = [0u8; 32]; @@ -2824,7 +2824,7 @@ fn literal_to_literal( } else if let Some(bin_digits) = orig_str.strip_prefix("0b") { let num_digits = bin_digits.chars().filter(|c| *c != '_').count(); match num_digits { - 1..=64 => Literal::U64(u64::try_from(parsed).unwrap()), + 1..=64 => Literal::Numeric(u64::try_from(parsed).unwrap()), 256 => { let bytes = parsed.to_bytes_be(); let mut full_bytes = [0u8; 32]; diff --git a/sway-core/src/type_system/engine.rs b/sway-core/src/type_system/engine.rs index 5c5bae35c8c..abe90214658 100644 --- a/sway-core/src/type_system/engine.rs +++ b/sway-core/src/type_system/engine.rs @@ -2,6 +2,7 @@ use core::fmt::Write; use hashbrown::hash_map::RawEntryMut; use hashbrown::HashMap; use std::sync::RwLock; +use sway_types::integer_bits::IntegerBits; use crate::concurrent_slab::ListDisplay; use crate::error::{err, ok}; @@ -259,6 +260,150 @@ impl TypeEngine { } } + /// Return whether a given type still contains undecayed references to [TypeInfo::Numeric] + pub(crate) fn contains_numeric(&self, decl_engine: &DeclEngine, type_id: TypeId) -> bool { + match &self.get(type_id) { + TypeInfo::Enum(decl_ref) => { + decl_engine + .get_enum(decl_ref) + .variants + .iter() + .all(|variant_type| { + self.contains_numeric(decl_engine, variant_type.type_argument.type_id) + }) + } + TypeInfo::Struct(decl_ref) => decl_engine + .get_struct(decl_ref) + .fields + .iter() + .any(|field| self.contains_numeric(decl_engine, field.type_argument.type_id)), + TypeInfo::Tuple(fields) => fields + .iter() + .any(|field_type| self.contains_numeric(decl_engine, field_type.type_id)), + TypeInfo::Array(elem_ty, _length) => { + self.contains_numeric(decl_engine, elem_ty.type_id) + } + TypeInfo::Ptr(targ) => self.contains_numeric(decl_engine, targ.type_id), + TypeInfo::Slice(targ) => self.contains_numeric(decl_engine, targ.type_id), + TypeInfo::Unknown + | TypeInfo::UnknownGeneric { .. } + | TypeInfo::Placeholder(..) + | TypeInfo::TypeParam(..) + | TypeInfo::Str(..) + | TypeInfo::UnsignedInteger(..) + | TypeInfo::Boolean + | TypeInfo::ContractCaller { .. } + | TypeInfo::Custom { .. } + | TypeInfo::SelfType + | TypeInfo::B256 + | TypeInfo::Contract + | TypeInfo::ErrorRecovery + | TypeInfo::Storage { .. } + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::Alias { .. } => false, + TypeInfo::Numeric => true, + } + } + + /// Resolve all inner types that still are a [TypeInfo::Numeric] to a concrete `u64` + pub(crate) fn decay_numeric( + &self, + engines: &Engines, + type_id: TypeId, + span: &Span, + ) -> CompileResult<()> { + let mut warnings = vec![]; + let mut errors = vec![]; + + let decl_engine = engines.de(); + + match &self.get(type_id) { + TypeInfo::Enum(decl_ref) => { + for variant_type in decl_engine.get_enum(decl_ref).variants.iter() { + check!( + self.decay_numeric(engines, variant_type.type_argument.type_id, span), + return err(warnings, errors), + warnings, + errors + ) + } + } + TypeInfo::Struct(decl_ref) => { + for field in decl_engine.get_struct(decl_ref).fields.iter() { + check!( + self.decay_numeric(engines, field.type_argument.type_id, span), + return err(warnings, errors), + warnings, + errors + ) + } + } + TypeInfo::Tuple(fields) => { + for field_type in fields { + check!( + self.decay_numeric(engines, field_type.type_id, span), + return err(warnings, errors), + warnings, + errors + ) + } + } + TypeInfo::Array(elem_ty, _length) => check!( + self.decay_numeric(engines, elem_ty.type_id, span), + return err(warnings, errors), + warnings, + errors + ), + TypeInfo::Ptr(targ) => check!( + self.decay_numeric(engines, targ.type_id, span), + return err(warnings, errors), + warnings, + errors + ), + TypeInfo::Slice(targ) => check!( + self.decay_numeric(engines, targ.type_id, span), + return err(warnings, errors), + warnings, + errors + ), + + TypeInfo::Unknown + | TypeInfo::UnknownGeneric { .. } + | TypeInfo::Placeholder(..) + | TypeInfo::TypeParam(..) + | TypeInfo::Str(..) + | TypeInfo::UnsignedInteger(..) + | TypeInfo::Boolean + | TypeInfo::ContractCaller { .. } + | TypeInfo::Custom { .. } + | TypeInfo::SelfType + | TypeInfo::B256 + | TypeInfo::Contract + | TypeInfo::ErrorRecovery + | TypeInfo::Storage { .. } + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::Alias { .. } => {} + TypeInfo::Numeric => { + check!( + CompileResult::from(self.unify( + engines, + type_id, + self.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), + span, + "", + None, + )), + (), + warnings, + errors, + ); + } + } + ok((), warnings, errors) + } + /// Resolve the type of the given [TypeId], replacing any instances of /// [TypeInfo::Custom] with either a monomorphized struct, monomorphized /// enum, or a reference to a type parameter. diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index bae9677e346..f1d2ab5278d 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -365,7 +365,7 @@ impl TypeId { span: &Span, trait_constraints: Vec, ) -> CompileResult<()> { - let warnings = vec![]; + let mut warnings = vec![]; let mut errors = vec![]; let engines = ctx.engines(); @@ -383,6 +383,16 @@ impl TypeId { continue; } + // resolving trait constraits require a concrete type, we need to default numeric to u64 + check!( + engines + .te() + .decay_numeric(engines, *structure_type_id, span), + return err(warnings, errors), + warnings, + errors + ); + let structure_type_info = engines.te().get(*structure_type_id); let structure_type_info_with_engines = engines.help_out(structure_type_info.clone()); if let TypeInfo::UnknownGeneric { diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index beeb6118c6b..2d73371ff11 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -898,7 +898,10 @@ impl TypeInfo { // whether they're actually asking 'is_aggregate()` or something else. matches!( self, - TypeInfo::Boolean | TypeInfo::UnsignedInteger(_) | TypeInfo::RawUntypedPtr + TypeInfo::Boolean + | TypeInfo::UnsignedInteger(_) + | TypeInfo::RawUntypedPtr + | TypeInfo::Numeric ) || self.is_unit() } diff --git a/sway-core/src/type_system/unify/unifier.rs b/sway-core/src/type_system/unify/unifier.rs index 7ad563114e3..d0cc60ddec8 100644 --- a/sway-core/src/type_system/unify/unifier.rs +++ b/sway-core/src/type_system/unify/unifier.rs @@ -1,10 +1,7 @@ use std::fmt; -use sway_error::{ - type_error::TypeError, - warning::{CompileWarning, Warning}, -}; -use sway_types::{integer_bits::IntegerBits, Ident, Span}; +use sway_error::{type_error::TypeError, warning::CompileWarning}; +use sway_types::{Ident, Span}; use crate::{engine_threading::*, language::ty, type_system::priv_prelude::*}; @@ -150,7 +147,7 @@ impl<'a> Unifier<'a> { // For integers and numerics, we (potentially) unify the numeric // with the integer. - (UnsignedInteger(r), UnsignedInteger(e)) => self.unify_unsigned_ints(span, r, e), + (UnsignedInteger(r), UnsignedInteger(e)) if r == e => (vec![], vec![]), (Numeric, e @ UnsignedInteger(_)) => { self.replace_received_with_expected(received, expected, &Numeric, e, span) } @@ -303,36 +300,6 @@ impl<'a> Unifier<'a> { (warnings, errors) } - fn unify_unsigned_ints( - &self, - span: &Span, - r: IntegerBits, - e: IntegerBits, - ) -> (Vec, Vec) { - // E.g., in a variable declaration `let a: u32 = 10u64` the 'expected' type will be - // the annotation `u32`, and the 'received' type is 'self' of the initialiser, or - // `u64`. So we're casting received TO expected. - let warnings = match numeric_cast_compat(e, r) { - NumericCastCompatResult::CastableWithWarning(warn) => { - vec![CompileWarning { - span: span.clone(), - warning_content: *warn, - }] - } - NumericCastCompatResult::Compatible => { - vec![] - } - }; - - // we don't want to do a slab replacement here, because - // we don't want to overwrite the original numeric type with the new one. - // This isn't actually inferencing the original type to the new numeric type. - // We just want to say "up until this point, this was a u32 (eg) and now it is a - // u64 (eg)". If we were to do a slab replace here, we'd be saying "this was always a - // u64 (eg)". - (warnings, vec![]) - } - fn unify_structs( &self, received: TypeId, @@ -437,29 +404,3 @@ impl<'a> Unifier<'a> { (r, e) } } - -fn numeric_cast_compat(new_size: IntegerBits, old_size: IntegerBits) -> NumericCastCompatResult { - // If this is a downcast, warn for loss of precision. If upcast, then no warning. - use IntegerBits::*; - match (new_size, old_size) { - // These should generate a downcast warning. - (Eight, Sixteen) - | (Eight, ThirtyTwo) - | (Eight, SixtyFour) - | (Sixteen, ThirtyTwo) - | (Sixteen, SixtyFour) - | (ThirtyTwo, SixtyFour) => { - NumericCastCompatResult::CastableWithWarning(Box::new(Warning::LossOfPrecision { - initial_type: old_size, - cast_to: new_size, - })) - } - // Upcasting is ok, so everything else is ok. - _ => NumericCastCompatResult::Compatible, - } -} - -enum NumericCastCompatResult { - Compatible, - CastableWithWarning(Box), -} diff --git a/sway-core/src/type_system/unify/unify_check.rs b/sway-core/src/type_system/unify/unify_check.rs index e517695d288..6cc9ca88450 100644 --- a/sway-core/src/type_system/unify/unify_check.rs +++ b/sway-core/src/type_system/unify/unify_check.rs @@ -627,7 +627,13 @@ impl<'a> UnifyCheck<'a> { let a = right_types.get(i).unwrap(); let b = right_types.get(j).unwrap(); if matches!(&self.mode, Coercion) - && (matches!(a, Placeholder(_)) || matches!(b, Placeholder(_))) + && (matches!( + (a, b), + (_, Placeholder(_)) + | (Placeholder(_), _) + | (UnsignedInteger(_), Numeric) + | (Numeric, UnsignedInteger(_)) + )) { continue; } @@ -641,7 +647,13 @@ impl<'a> UnifyCheck<'a> { let a = left_types.get(i).unwrap(); let b = left_types.get(j).unwrap(); if matches!(&self.mode, Coercion) - && (matches!(a, Placeholder(_)) || matches!(b, Placeholder(_))) + && (matches!( + (a, b), + (_, Placeholder(_)) + | (Placeholder(_), _) + | (UnsignedInteger(_), Numeric) + | (Numeric, UnsignedInteger(_)) + )) { continue; } diff --git a/sway-error/src/warning.rs b/sway-error/src/warning.rs index b7193c16597..c95e3337ff7 100644 --- a/sway-error/src/warning.rs +++ b/sway-error/src/warning.rs @@ -1,6 +1,6 @@ use core::fmt; -use sway_types::{integer_bits::IntegerBits, Ident, SourceId, Span, Spanned}; +use sway_types::{Ident, SourceId, Span, Spanned}; // TODO: since moving to using Idents instead of strings, // the warning_content will usually contain a duplicate of the span. @@ -52,10 +52,6 @@ pub enum Warning { NonScreamingSnakeCaseConstName { name: Ident, }, - LossOfPrecision { - initial_type: IntegerBits, - cast_to: IntegerBits, - }, UnusedReturnValue { r#type: String, }, @@ -177,12 +173,6 @@ impl fmt::Display for Warning { to_screaming_snake_case(name.as_str()), ) }, - LossOfPrecision { - initial_type, - cast_to, - } => write!(f, - "This cast, from integer type of width {initial_type} to integer type of width {cast_to}, will lose precision." - ), UnusedReturnValue { r#type } => write!( f, "This returns a value of type {type}, which is not assigned to anything and is \ diff --git a/sway-ir/src/error.rs b/sway-ir/src/error.rs index cc5382a88e6..985fd1e433a 100644 --- a/sway-ir/src/error.rs +++ b/sway-ir/src/error.rs @@ -23,7 +23,7 @@ pub enum IrError { VerifyBlockArgMalformed, VerifyBranchParamsMismatch, VerifyBranchToMissingBlock(String), - VerifyCallArgTypeMismatch(String), + VerifyCallArgTypeMismatch(String, String, String), VerifyCallToMissingFunction(String), VerifyCmpBadTypes(String, String), VerifyCmpTypeMismatch(String, String), @@ -136,10 +136,10 @@ impl fmt::Display for IrError { Branch to block '{label}' is not a block in the current function." ) } - IrError::VerifyCallArgTypeMismatch(callee) => { + IrError::VerifyCallArgTypeMismatch(callee, caller_ty, callee_ty) => { write!( f, - "Verification failed: Type mismatch found for call to '{callee}'." + "Verification failed: Type mismatch found for call to '{callee}': {caller_ty} is not a {callee_ty}." ) } IrError::VerifyCallToMissingFunction(callee) => { diff --git a/sway-ir/src/irtype.rs b/sway-ir/src/irtype.rs index 00031e13144..59f7f3f32eb 100644 --- a/sway-ir/src/irtype.rs +++ b/sway-ir/src/irtype.rs @@ -50,7 +50,6 @@ impl Type { Self::get_or_create_unique_type(context, TypeContent::Unit); Self::get_or_create_unique_type(context, TypeContent::Bool); Self::get_or_create_unique_type(context, TypeContent::Uint(8)); - Self::get_or_create_unique_type(context, TypeContent::Uint(32)); Self::get_or_create_unique_type(context, TypeContent::Uint(64)); Self::get_or_create_unique_type(context, TypeContent::B256); Self::get_or_create_unique_type(context, TypeContent::Slice); @@ -81,11 +80,6 @@ impl Type { Self::get_type(context, &TypeContent::Uint(8)).expect("create_basic_types not called") } - /// New u32 type - pub fn get_uint32(context: &Context) -> Type { - Self::get_type(context, &TypeContent::Uint(32)).expect("create_basic_types not called") - } - /// New u64 type pub fn get_uint64(context: &Context) -> Type { Self::get_type(context, &TypeContent::Uint(64)).expect("create_basic_types not called") diff --git a/sway-ir/src/verify.rs b/sway-ir/src/verify.rs index 673229b756e..94da9de6d9a 100644 --- a/sway-ir/src/verify.rs +++ b/sway-ir/src/verify.rs @@ -372,6 +372,8 @@ impl<'a, 'eng> InstructionVerifier<'a, 'eng> { if !caller_arg_type.eq(self.context, callee_arg_type) { return Err(IrError::VerifyCallArgTypeMismatch( callee_content.name.clone(), + caller_arg_type.as_string(self.context), + callee_arg_type.as_string(self.context), )); } } diff --git a/sway-lib-core/src/primitive_conversions.sw b/sway-lib-core/src/primitive_conversions.sw index 46d3f3b2d0c..3b302aff3d8 100644 --- a/sway-lib-core/src/primitive_conversions.sw +++ b/sway-lib-core/src/primitive_conversions.sw @@ -141,6 +141,12 @@ impl u64 { } impl u32 { + pub fn as_u64(self) -> u64 { + asm(input: self) { + input: u64 + } + } + pub fn to_le_bytes(self) -> [u8; 4] { let output = [0_u8, 0_u8, 0_u8, 0_u8]; @@ -213,6 +219,18 @@ impl u32 { } impl u16 { + pub fn as_u32(self) -> u32 { + asm(input: self) { + input: u32 + } + } + + pub fn as_u64(self) -> u64 { + asm(input: self) { + input: u64 + } + } + pub fn to_le_bytes(self) -> [u8; 2] { let output = [0_u8, 0_u8]; @@ -259,6 +277,26 @@ impl u16 { } } +impl u8 { + pub fn as_u16(self) -> u16 { + asm(input: self) { + input: u16 + } + } + + pub fn as_u32(self) -> u32 { + asm(input: self) { + input: u32 + } + } + + pub fn as_u64(self) -> u64 { + asm(input: self) { + input: u64 + } + } +} + impl b256 { pub fn to_le_bytes(self) -> [u8; 32] { let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) {r1: (u64, u64, u64, u64)}; @@ -463,7 +501,7 @@ fn test_b256_to_le_bytes() { let mut i: u8 = 0; while i < 32_u8 { - assert(bytes[i] == 32_u8 - i); + assert(bytes[i.as_u64()] == 32_u8 - i); i += 1_u8; } @@ -489,7 +527,7 @@ fn test_b256_to_be_bytes() { let mut i: u8 = 0; while i < 32_u8 { - assert(bytes[i] == i + 1_u8); + assert(bytes[i.as_u64()] == i + 1_u8); i += 1_u8; } } diff --git a/sway-lib-core/src/primitives.sw b/sway-lib-core/src/primitives.sw index 037e7c03f3a..fca12d7d19f 100644 --- a/sway-lib-core/src/primitives.sw +++ b/sway-lib-core/src/primitives.sw @@ -13,7 +13,7 @@ impl u64 { } /// The size of this integer type in bits. - pub fn bits() -> u32 { + pub fn bits() -> u64 { 64 } } @@ -31,7 +31,7 @@ impl u32 { } /// The size of this integer type in bits. - pub fn bits() -> u32 { + pub fn bits() -> u64 { 32 } } @@ -49,7 +49,7 @@ impl u16 { } /// The size of this integer type in bits. - pub fn bits() -> u32 { + pub fn bits() -> u64 { 16 } } @@ -67,7 +67,7 @@ impl u8 { } /// The size of this integer type in bits. - pub fn bits() -> u32 { + pub fn bits() -> u64 { 8 } } diff --git a/sway-lib-std/src/auth.sw b/sway-lib-std/src/auth.sw index 943bd091da6..fb6472ca68d 100644 --- a/sway-lib-std/src/auth.sw +++ b/sway-lib-std/src/auth.sw @@ -52,7 +52,7 @@ fn inputs_owner() -> Result { // Note: `inputs_count` is guaranteed to be at least 1 for any valid tx. while i < inputs { - let type_of_input = input_type(i); + let type_of_input = input_type(i.as_u64()); match type_of_input { Input::Coin => (), Input::Message => (), @@ -64,7 +64,7 @@ fn inputs_owner() -> Result { } // type == InputCoin or InputMessage. - let owner_of_input = input_owner(i); + let owner_of_input = input_owner(i.as_u64()); if candidate.is_none() { // This is the first input seen of the correct type. candidate = owner_of_input; diff --git a/sway-lib-std/src/inputs.sw b/sway-lib-std/src/inputs.sw index f93d270417f..dc77afa16bf 100644 --- a/sway-lib-std/src/inputs.sw +++ b/sway-lib-std/src/inputs.sw @@ -18,6 +18,7 @@ use ::tx::{ tx_type, }; use core::ops::Eq; +use core::primitive_conversions::*; const GTF_INPUT_TYPE = 0x101; @@ -203,7 +204,7 @@ pub fn input_predicate(index: u64) -> Bytes { if wrapped.is_none() { revert(0); }; - let length = wrapped.unwrap(); + let length = wrapped.unwrap().as_u64(); let mut data_bytes = Bytes::with_capacity(length); match input_predicate_pointer(index) { Some(d) => { @@ -265,7 +266,7 @@ pub fn input_message_data(index: u64, offset: u64) -> Bytes { assert(valid_input_type(index, Input::Message)); let data = __gtf::(index, GTF_INPUT_MESSAGE_DATA); let data_with_offset = data.add_uint_offset(offset); - let length = input_message_data_length(index); + let length = input_message_data_length(index).as_u64(); let mut data_bytes = Bytes::with_capacity(length); data_bytes.len = length; data_with_offset.copy_bytes_to(data_bytes.buf.ptr, length); diff --git a/sway-lib-std/src/lib.sw b/sway-lib-std/src/lib.sw index 466a5d5f44f..ac571373d90 100644 --- a/sway-lib-std/src/lib.sw +++ b/sway-lib-std/src/lib.sw @@ -5,6 +5,7 @@ pub mod logging; pub mod revert; pub mod result; pub mod option; +pub mod primitive_conversions; pub mod convert; pub mod intrinsics; pub mod assert; diff --git a/sway-lib-std/src/prelude.sw b/sway-lib-std/src/prelude.sw index 54c64a4748e..cea7c1c95c9 100644 --- a/sway-lib-std/src/prelude.sw +++ b/sway-lib-std/src/prelude.sw @@ -24,6 +24,9 @@ use ::revert::{require, revert}; // Convert use ::convert::From; +// Primitive conversions +use ::primitive_conversions::*; + // Logging use ::logging::log; diff --git a/sway-lib-std/src/primitive_conversions.sw b/sway-lib-std/src/primitive_conversions.sw new file mode 100644 index 00000000000..cf8145ac354 --- /dev/null +++ b/sway-lib-std/src/primitive_conversions.sw @@ -0,0 +1,70 @@ +library; + +use ::option::Option::{self, *}; +use core::primitive_conversions::*; + +impl u16 { + pub fn try_as_u8(self) -> Option { + if self <= u8::max().as_u16() { + Some(asm(input: self) { + input: u8 + }) + } else { + None + } + } +} + +impl u32 { + pub fn try_as_u8(self) -> Option { + if self <= u8::max().as_u32() { + Some(asm(input: self) { + input: u8 + }) + } else { + None + } + } + + pub fn try_as_u16(self) -> Option { + if self <= u16::max().as_u32() { + Some(asm(input: self) { + input: u16 + }) + } else { + None + } + } +} + +impl u64 { + pub fn try_as_u8(self) -> Option { + if self <= u8::max().as_u64() { + Some(asm(input: self) { + input: u8 + }) + } else { + None + } + } + + pub fn try_as_u16(self) -> Option { + if self <= u16::max().as_u64() { + Some(asm(input: self) { + input: u16 + }) + } else { + None + } + } + + pub fn try_as_u32(self) -> Option { + if self <= u32::max().as_u64() { + Some(asm(input: self) { + input: u32 + }) + } else { + None + } + } +} diff --git a/sway-lsp/tests/fixtures/tokens/consts/src/more_consts.sw b/sway-lsp/tests/fixtures/tokens/consts/src/more_consts.sw index 70cb2eecec2..732d3698c06 100644 --- a/sway-lsp/tests/fixtures/tokens/consts/src/more_consts.sw +++ b/sway-lsp/tests/fixtures/tokens/consts/src/more_consts.sw @@ -9,6 +9,6 @@ enum Data { B: Value, } -pub const CONSTANT_3: u32 = 300; +pub const CONSTANT_3: u64 = 300; pub const CONSTANT_4: u32 = 400; pub const MY_DATA1: Data = Data::A(true); diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/abort_control_flow_bad/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/abort_control_flow_bad/test.toml index 95441264e4e..ddc167398e4 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/abort_control_flow_bad/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/abort_control_flow_bad/test.toml @@ -3,7 +3,7 @@ category = "fail" # check: return 42; # nextln: $()Mismatched types. # nextln: $()expected: () -# nextln: $()found: u64. +# nextln: $()found: numeric. # nextln: $()help: Return statement must return the declared function return type. # This 'return true' line appears in both error messages.. diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/src/main.sw index 723a63c7ba7..b7ae6bbaced 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/src/main.sw @@ -9,5 +9,9 @@ fn main() { let _ = __add("Hello", 22); let _ = __add("Hello", "Hello"); let _ = __add(false, true); + let _ = __add(1u32, 1u64); let _ = __add::(0, 1); + + let _ = __rsh("Hello", 1); + let _ = __rsh(1, "Hello"); } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/test.toml index d57ccbfb9af..622e160e972 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/test.toml @@ -2,20 +2,67 @@ category = "fail" # check: $()error # check: $()__add(A { a: 32 }, 32); -# nextln: $()Unsupported argument type to intrinsic "add" +# nextln: $()Mismatched types +# nextln: $()expected: numeric +# nextln: $()found: A. +# nextln: $()help: Incorrect argument type # check: $()error # check: $()__add("Hello", 22); -# nextln: $()Unsupported argument type to intrinsic "add" +# nextln: $()Mismatched types +# nextln: $()expected: numeric +# nextln: $()found: str[5]. +# nextln: $()help: Incorrect argument type # check: $()error # check: $()__add("Hello", "Hello") -# nextln: $()Unsupported argument type to intrinsic "add" +# nextln: $()Mismatched types +# nextln: $()expected: numeric +# nextln: $()found: str[5]. +# nextln: $()help: Incorrect argument type + +# check: $()error +# check: $()__add("Hello", "Hello") +# nextln: $()Mismatched types +# nextln: $()expected: numeric +# nextln: $()found: str[5]. +# nextln: $()help: Incorrect argument type + +# check: $()error +# check: $()__add(false, true) +# nextln: $()Mismatched types +# nextln: $()expected: numeric +# nextln: $()found: bool. +# nextln: $()help: Incorrect argument type # check: $()error # check: $()__add(false, true) -# nextln: $()Unsupported argument type to intrinsic "add" +# nextln: $()Mismatched types +# nextln: $()expected: numeric +# nextln: $()found: bool. +# nextln: $()help: Incorrect argument type + +# check: $()error +# check: $()__add(1u32, 1u64) +# nextln: $()Mismatched types +# nextln: $()expected: u32 +# nextln: $()found: u64. +# nextln: $()help: Incorrect argument type # check: $()error # check: $()__add::(0, 1) -# nextln: $()Call to "add" expects 0 type arguments \ No newline at end of file +# nextln: $()Call to "add" expects 0 type arguments + +# check: $()error +# check: $()__rsh("Hello", 1) +# nextln: $()Mismatched types +# nextln: $()expected: numeric +# nextln: $()found: str[5]. +# nextln: $()help: Incorrect argument type + +# check: $()error +# check: $()__rsh(1, "Hello") +# nextln: $()Mismatched types +# nextln: $()expected: numeric +# nextln: $()found: str[5]. +# nextln: $()help: Incorrect argument type diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/eq_intrinsic/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/eq_intrinsic/src/main.sw index f0af6b19049..565bb606bdb 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/eq_intrinsic/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/eq_intrinsic/src/main.sw @@ -13,6 +13,7 @@ fn main() { let _ = __eq("hi", "ho"); let _ = __eq(false, 11); let _ = __eq(A { a: 1 }, B { a: 1 }); + let _ = __eq(A { a: 1 }, A { a: 1 }); let _ = __eq((1, 2), (1, 2)); let _ = __eq([1, 2], [1, 2]); let _ = __eq(B::First, B::First); diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/eq_intrinsic/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/eq_intrinsic/test.toml index 299b8ccd092..0e2ed113c0b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/eq_intrinsic/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/eq_intrinsic/test.toml @@ -1,12 +1,20 @@ category = "fail" # check: $()__eq("hi", "ho"); -# nextln: $()Unsupported argument type to intrinsic "eq". +# check: $()Unsupported argument type to intrinsic "eq". + +# check: $()__eq(false, 11); # check: $()__eq(false, 11); # check: $()Mismatched types. +# check: $()expected: bool +# check: $()found: numeric. +# check: $()help: Variable declaration's type annotation does not match up with the assigned expression's type. # check: $()__eq(A { a: 1 }, B { a: 1 }); +# check: $()This is a B, not a struct. + +# check: $()__eq(A { a: 1 }, A { a: 1 }); # check: $()Unsupported argument type to intrinsic "eq". # check: $()__eq((1, 2), (1, 2)); diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/match_expressions_wrong_struct/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/match_expressions_wrong_struct/test.toml index a65a07466bc..af2d7912fad 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/match_expressions_wrong_struct/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/match_expressions_wrong_struct/test.toml @@ -2,14 +2,14 @@ category = "fail" # check: Point { x: 3, y } => { y }, # nextln: $()Mismatched types. -# nextln: $()expected: u64 +# nextln: $()expected: numeric # nextln: $()found: Point. # check: Point { x: 3, y: 4 } => { 24 }, # check: Point { x: 3, y: 4 } => { 24 }, # nextln: $()Mismatched types. -# nextln: $()expected: u64 +# nextln: $()expected: numeric # nextln: $()found: Point. # check: Data { value: 1u64 } => { false }, diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/where_clause_impls/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/where_clause_impls/src/main.sw index bd52fd9a806..c5d356b113a 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/where_clause_impls/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/where_clause_impls/src/main.sw @@ -46,11 +46,11 @@ impl MyAdd for MyPoint { fn main() -> u8 { let foo = MyPoint { x: 1u32, - y: 2u64, + y: 2u32, }; let bar = MyPoint { x: 3u32, - y: 4u64, + y: 4u32, }; let baz = foo.my_add(bar); baz.y diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/wrongly_sized_tuple_destructuring/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/wrongly_sized_tuple_destructuring/test.toml index 3b3a09f51f8..665eaf32ad9 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/wrongly_sized_tuple_destructuring/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/wrongly_sized_tuple_destructuring/test.toml @@ -3,5 +3,5 @@ category = "fail" # check: let (_b, _c) = a; # nextln: $()Mismatched types. # nextln: $()expected: (_, _) -# nextln: $()found: (bool, u64, u64). +# nextln: $()found: (bool, numeric, numeric). # nextln: $()help: Variable declaration's type annotation does not match up with the assigned expression's type. diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_impl_local_same_name/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_impl_local_same_name/src/main.sw index 41e7bf3be8a..7b4dcb452e8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_impl_local_same_name/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_impl_local_same_name/src/main.sw @@ -6,7 +6,7 @@ impl Struct { const ID: u32 = 1; } -fn main() -> u64 { +fn main() -> u32 { const ID: u32 = 1; Struct::ID } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_impl_multiple/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_impl_multiple/src/main.sw index 911e86b220a..69e2d6266f5 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_impl_multiple/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_impl_multiple/src/main.sw @@ -10,6 +10,6 @@ impl Struct { const ID2: u32 = 2; } -fn main() -> u64 { +fn main() -> u32 { Struct::ID } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/src/main.sw index 61f76380f30..db4675d4f7f 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/src/main.sw @@ -56,6 +56,7 @@ fn main() -> u64 { assert(__lsh(2, 3) == 16); assert(__rsh(16, 3) == 2); assert(__rsh(1, 1) == 0); + assert(__rsh(1u8, 1u64) == 0); 2 } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/fix_opcode_bug/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/fix_opcode_bug/json_abi_oracle.json index 13de84b092b..ad50b55d54c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/fix_opcode_bug/json_abi_oracle.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/fix_opcode_bug/json_abi_oracle.json @@ -17,7 +17,7 @@ "types": [ { "components": null, - "type": "u32", + "type": "u64", "typeId": 0, "typeParameters": null } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/fix_opcode_bug/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/fix_opcode_bug/src/main.sw index 62745e5a3c0..e8d193b4a01 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/fix_opcode_bug/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/fix_opcode_bug/src/main.sw @@ -120,7 +120,7 @@ fn where_x() -> u64 { return 1; } -fn main() -> u32 { +fn main() -> u64 { let where_y = abi_x() + enum_x() + fn_x() diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_functions/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_functions/src/main.sw index b483a38d634..356dab7abca 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_functions/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_functions/src/main.sw @@ -15,7 +15,7 @@ fn three_generics(a: A, b: B, _c: C) -> B { fn main() -> bool { let a: bool = identity(true); - let _b: u32 = identity(10); + let _b: u32 = identity(10u32); let _c: u64 = identity(42); let _e: str[3] = identity("foo"); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_impl_self/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_impl_self/src/main.sw index 87c0135d9ee..c40a7312e06 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_impl_self/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_impl_self/src/main.sw @@ -166,7 +166,7 @@ fn generic_impl_self_test() { assert(f.first && f.second); let g: DoubleIdentity = double_identity(10u32, 43u64); - assert((g.first + 33u32) == g.second); + assert((g.first + 33u32).as_u64() == g.second); let h = DoubleIdentity::::new(3u64, false); assert(!h.second); @@ -182,10 +182,10 @@ fn generic_impl_self_test() { let m: DoubleIdentity, Data> = DoubleIdentity { first: Data { value: 1u8 }, - second: Data { value: 2u8 }, + second: Data { value: 2u64 }, third: 1u64, }; - assert(m.second.value == (m.first.value + m.third)); + assert(m.second.value == (m.first.value.as_u64() + m.third)); let n = DoubleIdentity::, Data>::new(Data::::new(3u8), Data::::new(4u8)); assert(n.third == 10u64); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_traits/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_traits/src/main.sw index 264ee4dbe24..3e5e72a76e3 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_traits/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_traits/src/main.sw @@ -41,34 +41,24 @@ trait MyAdd { fn my_add(self, a: T, b: T) -> T; } -// impl MyAdd for FooBarData { -// fn my_add(self, a: u8, b: u8) -> u8 { -// a + b -// } -// } - -impl MyAdd for FooBarData { - fn my_add(self, a: u64, b: u64) -> u64 { +impl MyAdd for FooBarData { + fn my_add(self, a: u8, b: u8) -> u8 { a + b } } +// impl MyAdd for FooBarData { +// fn my_add(self, a: u64, b: u64) -> u64 { +// a + b +// } +// } + trait MySub { fn my_sub(a: T, b: T) -> T; } -// impl MySub for FooBarData { -// fn my_sub(a: u8, b: u8) -> u8 { -// if a >= b { -// a - b -// } else { -// b - a -// } -// } -// } - -impl MySub for FooBarData { - fn my_sub(a: u64, b: u64) -> u64 { +impl MySub for FooBarData { + fn my_sub(a: u8, b: u8) -> u8 { if a >= b { a - b } else { @@ -77,35 +67,35 @@ impl MySub for FooBarData { } } +// impl MySub for FooBarData { +// fn my_sub(a: u64, b: u64) -> u64 { +// if a >= b { +// a - b +// } else { +// b - a +// } +// } +// } + struct OtherData { a: T, b: T, } -// impl MyAdd for OtherData { -// fn my_add(self, a: u8, b: u8) -> u8 { -// a + b -// } -// } - -impl MyAdd for OtherData { - fn my_add(self, a: u64, b: u64) -> u64 { +impl MyAdd for OtherData { + fn my_add(self, a: u8, b: u8) -> u8 { a + b } } -// impl MySub for OtherData { -// fn my_sub(a: u8, b: u8) -> u8 { -// if a >= b { -// a - b -// } else { -// b - a -// } +// impl MyAdd for OtherData { +// fn my_add(self, a: u64, b: u64) -> u64 { +// a + b // } // } -impl MySub for OtherData { - fn my_sub(a: u64, b: u64) -> u64 { +impl MySub for OtherData { + fn my_sub(a: u8, b: u8) -> u8 { if a >= b { a - b } else { @@ -114,6 +104,16 @@ impl MySub for OtherData { } } +// impl MySub for OtherData { +// fn my_sub(a: u64, b: u64) -> u64 { +// if a >= b { +// a - b +// } else { +// b - a +// } +// } +// } + impl MyTriple for MyPoint { fn my_triple(self, value: u64) -> u64 { (self.x*3) + (self.y*3) + (value*3) diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/integer_type_inference/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/integer_type_inference/Forc.lock index 217fd64e29d..a545615d3ad 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/integer_type_inference/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/integer_type_inference/Forc.lock @@ -1,3 +1,13 @@ +[[package]] +name = 'core' +source = 'path+from-root-5D74C309D88B9A80' + [[package]] name = 'integer_type_inference' source = 'member' +dependencies = ['std'] + +[[package]] +name = 'std' +source = 'path+from-root-5D74C309D88B9A80' +dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/integer_type_inference/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/integer_type_inference/Forc.toml index 8e2af8ea944..ac2acc44fac 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/integer_type_inference/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/integer_type_inference/Forc.toml @@ -4,3 +4,6 @@ entry = "main.sw" implicit-std = false license = "Apache-2.0" name = "integer_type_inference" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/integer_type_inference/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/integer_type_inference/src/main.sw index bc55e91440a..808acf132f2 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/integer_type_inference/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/integer_type_inference/src/main.sw @@ -2,28 +2,16 @@ script; /* Test Constants */ const X1: u8 = 4u8; -const X2: u8 = 4u16; -const X3: u8 = 4u32; -const X4: u8 = 4u64; -const X5: u8 = 4; - -const Y1: u16 = 4u8; -const Y2: u16 = 4u16; -const Y3: u16 = 4u32; -const Y4: u16 = 4u64; -const Y5: u16 = 4; - -const Z1: u32 = 4u8; -const Z2: u32 = 4u16; -const Z3: u32 = 4u32; -const Z4: u32 = 4u64; -const Z5: u32 = 4; - -const W1: u64 = 4u8; -const W2: u64 = 4u16; -const W3: u64 = 4u32; -const W4: u64 = 4u64; -const W5: u64 = 4; +const X2: u8 = 4; + +const Y1: u16 = 4u16; +const Y2: u16 = 4; + +const Z1: u32 = 4u32; +const Z2: u32 = 4; + +const W1: u64 = 4u64; +const W2: u64 = 4; const V1 = 4u8; const V2 = 4u16; @@ -69,27 +57,15 @@ fn main() { /* Make sure that the resulting types of constants are correct */ X1.foo_u8(); X2.foo_u8(); - X3.foo_u8(); - X4.foo_u8(); - X5.foo_u8(); Y1.foo_u16(); Y2.foo_u16(); - Y3.foo_u16(); - Y4.foo_u16(); - Y5.foo_u16(); Z1.foo_u32(); Z2.foo_u32(); - Z3.foo_u32(); - Z4.foo_u32(); - Z5.foo_u32(); W1.foo_u64(); W2.foo_u64(); - W3.foo_u64(); - W4.foo_u64(); - W5.foo_u64(); V1.foo_u8(); V2.foo_u16(); @@ -99,26 +75,26 @@ fn main() { /* Make sure that the resulting types of variables are correct */ let x1: u8 = 4u8; - let x2: u8 = 4u16; - let x3: u8 = 4u32; - let x4: u8 = 4u64; + let x2: u8 = 4u16.try_as_u8().unwrap(); + let x3: u8 = 4u32.try_as_u8().unwrap(); + let x4: u8 = 4u64.try_as_u8().unwrap(); let x5: u8 = 4; - let y1: u16 = 4u8; + let y1: u16 = 4u8.as_u16(); let y2: u16 = 4u16; - let y3: u16 = 4u32; - let y4: u16 = 4u64; + let y3: u16 = 4u32.try_as_u16().unwrap(); + let y4: u16 = 4u64.try_as_u16().unwrap(); let y5: u16 = 4; - let z1: u32 = 4u8; - let z2: u32 = 4u16; + let z1: u32 = 4u8.as_u32(); + let z2: u32 = 4u16.as_u32(); let z3: u32 = 4u32; - let z4: u32 = 4u64; + let z4: u32 = 4u64.try_as_u32().unwrap(); let z5: u32 = 4; - let w1: u64 = 4u8; - let w2: u64 = 4u16; - let w3: u64 = 4u32; + let w1: u64 = 4u8.as_u64(); + let w2: u64 = 4u16.as_u64(); + let w3: u64 = 4u32.as_u64(); let w4: u64 = 4u64; let w5: u64 = 4; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/numeric_constants/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/numeric_constants/src/main.sw index faaa429503f..855f039ded8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/numeric_constants/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/numeric_constants/src/main.sw @@ -1,18 +1,19 @@ script; fn main() -> bool { - assert(u64::max() == 18446744073709551615); + assert(u64::max() == 18446744073709551615u64); assert(u64::min() == 0u64); - assert(u64::bits() == 64u32); assert(u32::max() == 4294967295u32); assert(u32::min() == 0u32); - assert(u32::bits() == 32u16); assert(u16::max() == 65535u16); assert(u16::min() == 0u16); - assert(u16::bits() == 16u8); assert(u8::max() == 255u8); assert(u8::min() == 0u8); - assert(u8::bits() == 8u32); + + assert(u64::bits() == 64u64); + assert(u32::bits() == 32u64); + assert(u16::bits() == 16u64); + assert(u8::bits() == 8u64); true } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/json_abi_oracle.json index 13de84b092b..ad50b55d54c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/json_abi_oracle.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/json_abi_oracle.json @@ -17,7 +17,7 @@ "types": [ { "components": null, - "type": "u32", + "type": "u64", "typeId": 0, "typeParameters": null } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/src/main.sw index 79bb2f2f505..6dfe0930cb8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/src/main.sw @@ -8,7 +8,7 @@ fn test(a: T, b: E) { let (_x, _y): (T, E) = (a, b); } -fn main() -> u32 { +fn main() -> u64 { let (_foo, _bar) = gimme_a_pair(); let (_x, _y): (u32, bool) = (10, true); //let (x, y): (u32, _) = (42, true); // this generates a parsing error diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/use_full_path_names/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/use_full_path_names/json_abi_oracle.json index ad50b55d54c..13de84b092b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/use_full_path_names/json_abi_oracle.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/use_full_path_names/json_abi_oracle.json @@ -17,7 +17,7 @@ "types": [ { "components": null, - "type": "u64", + "type": "u32", "typeId": 0, "typeParameters": null } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/use_full_path_names/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/use_full_path_names/src/main.sw index 49b297b87bc..3958527e82d 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/use_full_path_names/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/use_full_path_names/src/main.sw @@ -4,7 +4,7 @@ mod foo; mod bar; mod baz; -fn main() -> u64 { +fn main() -> u32 { let _x = foo::Foo { foo: 1u32, }; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/vec/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/vec/src/main.sw index b1ec2f569bc..28a2fce7c59 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/vec/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/vec/src/main.sw @@ -67,7 +67,7 @@ fn test_vector_new_u8() { Some(val) => assert(val == number4), None => revert(0), } - match vector.get(number6) { + match vector.get(number6.as_u64()) { Some(val) => assert(val == number6), None => revert(0), } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_1512_repro/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_1512_repro/Forc.lock index 5fea31fe7e0..0c3961f4fed 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_1512_repro/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_1512_repro/Forc.lock @@ -5,4 +5,12 @@ source = 'path+from-root-C086F5BB5B0BA300' [[package]] name = 'issue_1512_repro' source = 'member' +dependencies = [ + 'core', + 'std', +] + +[[package]] +name = 'std' +source = 'path+from-root-C086F5BB5B0BA300' dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_1512_repro/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_1512_repro/Forc.toml index e4b5416944c..76aa7d7c5b0 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_1512_repro/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_1512_repro/Forc.toml @@ -7,3 +7,4 @@ name = "issue_1512_repro" [dependencies] core = { path = "../../../../../../../sway-lib-core" } +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_1512_repro/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_1512_repro/src/main.sw index 52435b6e956..ffdf6ebd0b4 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_1512_repro/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_1512_repro/src/main.sw @@ -17,7 +17,7 @@ pub struct U128 { lower: u64, } -pub trait From { +pub trait AltFrom { fn from(h: u64, l: u64) -> Self; } { } @@ -29,7 +29,7 @@ impl core::ops::Eq for U128 { } /// Function for creating U128 from its u64 components -impl From for U128 { +impl AltFrom for U128 { fn from(h: u64, l: u64) -> U128 { U128 { upper: h, @@ -91,28 +91,28 @@ impl U128 { // TO DO : mul, div, inequalities, etc. } -// Downcast from u64 to u32, losing precision -fn u64_to_u32(a: u64) -> u32 { - let result: u32 = a; - result -} - // Multiply two u64 values, producing a U128 pub fn mul64(a: u64, b: u64) -> U128 { // Split a and b into 32-bit lo and hi components - let a_lo = u64_to_u32(a); - let a_hi = u64_to_u32(a >> 32); - let b_lo = u64_to_u32(b); - let b_hi = u64_to_u32(b >> 32); + let a_lo = (a & 0x00000000ffffffff).try_as_u32().unwrap(); + let a_hi = (a >> 32).try_as_u32().unwrap(); + let b_lo = (b & 0x00000000ffffffff).try_as_u32().unwrap(); + let b_hi = (b >> 32).try_as_u32().unwrap(); // Calculate low, high, and mid multiplications - let ab_hi: u64 = a_hi * b_hi; - let ab_mid: u64 = a_hi * b_lo; - let ba_mid: u64 = b_hi * a_lo; - let ab_lo: u64 = a_lo * b_lo; + let ab_hi = (a_hi * b_hi).as_u64(); + let ab_mid = (a_hi * b_lo).as_u64(); + let ba_mid = (b_hi * a_lo).as_u64(); + let ab_lo = (a_lo * b_lo).as_u64(); // Calculate the carry bit - let carry_bit: u64 = (u64_to_u32(ab_mid) + u64_to_u32(ba_mid) + (ab_lo >> 32)) >> 32; + let carry_bit = ( + ( + ab_mid.try_as_u32().unwrap() + + ba_mid.try_as_u32().unwrap() + + (ab_lo >> 32).try_as_u32().unwrap() + ) >> 32 + ).as_u64(); // low result is what's left after the (overflowing) multiplication of a and b let result_lo: u64 = a * b; diff --git a/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw index 72236b30040..927ed49f50c 100644 --- a/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw @@ -73,7 +73,7 @@ impl TxContractTest for Contract { tx_script_data_length() } fn get_tx_inputs_count() -> u64 { - input_count() + input_count().as_u64() } fn get_tx_outputs_count() -> u64 { output_count() @@ -154,7 +154,7 @@ impl TxContractTest for Contract { fn get_input_predicate(index: u64, bytecode: Vec) -> bool { let code = input_predicate(index); - assert(input_predicate_length(index).unwrap() == bytecode.len()); + assert(input_predicate_length(index).unwrap().as_u64() == bytecode.len()); let mut i = 0; while i < bytecode.len() { assert(bytecode.get(i).unwrap() == code.get(i).unwrap()); diff --git a/test/src/sdk-harness/test_projects/generics_in_abi/src/main.sw b/test/src/sdk-harness/test_projects/generics_in_abi/src/main.sw index 4077bd588d2..1af16c7f2ad 100644 --- a/test/src/sdk-harness/test_projects/generics_in_abi/src/main.sw +++ b/test/src/sdk-harness/test_projects/generics_in_abi/src/main.sw @@ -79,7 +79,7 @@ impl MyContract for Contract { } fn struct_w_generic_in_tuple(arg1: StructWTupleGeneric) -> StructWTupleGeneric { - let expected = StructWTupleGeneric { a: (1, 2) }; + let expected = StructWTupleGeneric { a: (1u32, 2u32) }; assert(expected.a.0 == arg1.a.0); assert(expected.a.1 == arg1.a.1); @@ -89,7 +89,7 @@ impl MyContract for Contract { fn struct_w_diff_generic_in_tuple( arg1: StructWDiffTupleGeneric, ) -> StructWDiffTupleGeneric { - let expected = StructWDiffTupleGeneric { a: (1, false) }; + let expected = StructWDiffTupleGeneric { a: (1u32, false) }; assert(expected.a.0 == arg1.a.0); assert(expected.a.1 == arg1.a.1); diff --git a/test/src/sdk-harness/test_projects/token_ops/src/main.sw b/test/src/sdk-harness/test_projects/token_ops/src/main.sw index 50fb8a120b6..6c476446319 100644 --- a/test/src/sdk-harness/test_projects/token_ops/src/main.sw +++ b/test/src/sdk-harness/test_projects/token_ops/src/main.sw @@ -62,9 +62,9 @@ impl TestFuelCoin for Contract { fn send_message(recipient: b256, msg_data: Vec, coins: u64) { let mut data = Bytes::new(); if msg_data.len() > 0 { - data.push(msg_data.get(0).unwrap()); - data.push(msg_data.get(1).unwrap()); - data.push(msg_data.get(2).unwrap()); + data.push(msg_data.get(0).unwrap().try_as_u8().unwrap()); + data.push(msg_data.get(1).unwrap().try_as_u8().unwrap()); + data.push(msg_data.get(2).unwrap().try_as_u8().unwrap()); } send_message(recipient, data, coins);