diff --git a/aptos-move/e2e-move-tests/src/tests/mod.rs b/aptos-move/e2e-move-tests/src/tests/mod.rs index 282a049e5e04a..7b46127a56d37 100644 --- a/aptos-move/e2e-move-tests/src/tests/mod.rs +++ b/aptos-move/e2e-move-tests/src/tests/mod.rs @@ -52,6 +52,7 @@ mod object_code_deployment; mod offer_rotation_capability; mod offer_signer_capability; mod per_category_gas_limits; +mod public_structs_enums_upgrade; mod randomness_test_and_abort; mod remote_state; mod resource_groups; diff --git a/aptos-move/e2e-move-tests/src/tests/public_structs_enums_upgrade.rs b/aptos-move/e2e-move-tests/src/tests/public_structs_enums_upgrade.rs new file mode 100644 index 0000000000000..7f612edafcb5c --- /dev/null +++ b/aptos-move/e2e-move-tests/src/tests/public_structs_enums_upgrade.rs @@ -0,0 +1,213 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +//! Tests for upgrade compatibility of public/package structs/enums + +use crate::{assert_success, assert_vm_status, MoveHarness}; +use aptos_framework::BuildOptions; +use aptos_language_e2e_tests::account::Account; +use aptos_package_builder::PackageBuilder; +use aptos_types::{account_address::AccountAddress, transaction::TransactionStatus}; +use move_core_types::vm_status::StatusCode; + +#[test] +fn public_enum_upgrade() { + let mut h = MoveHarness::new(); + let acc = h.new_account_at(AccountAddress::from_hex_literal("0x815").unwrap()); + + let result = publish( + &mut h, + &acc, + r#" + module 0x815::m { + enum Data { + V1{x: u64} + } + } + "#, + ); + assert_success!(result); + + let result = publish( + &mut h, + &acc, + r#" + module 0x815::m { + public enum Data { + V1{x: u64}, + V2{x: u64, y: u8}, + } + } + "#, + ); + assert_success!(result); + + let result = publish( + &mut h, + &acc, + r#" + module 0x815::m { + enum Data { + V1{x: u64}, + V2{x: u64, y: u8}, + } + } + "#, + ); + assert_vm_status!(result, StatusCode::BACKWARD_INCOMPATIBLE_MODULE_UPDATE); + + let result = publish( + &mut h, + &acc, + r#" + module 0x815::m { + package enum Data { + V1{x: u64}, + V2{x: u64, y: u8}, + } + } + "#, + ); + assert_vm_status!(result, StatusCode::BACKWARD_INCOMPATIBLE_MODULE_UPDATE); +} + +#[test] +fn friend_enum_struct_upgrade() { + let mut h = MoveHarness::new(); + let acc = h.new_account_at(AccountAddress::from_hex_literal("0x815").unwrap()); + + let result = publish( + &mut h, + &acc, + r#" + module 0x815::m { + friend 0x815::m2; + enum Data { + V1{x: u64} + } + } + module 0x815::m2 { + } + "#, + ); + assert_success!(result); + + let result = publish( + &mut h, + &acc, + r#" + module 0x815::m2 { + use 0x815::m::Data; + fun get_data(): Data { + Data::V2{x: 1, y: 2} + } + } + module 0x815::m { + friend 0x815::m2; + friend enum Data { + V1{x: u64}, + V2{x: u64, y: u8}, + } + } + "#, + ); + assert_success!(result); + + let result = publish( + &mut h, + &acc, + r#" + module 0x815::m2 { + } + module 0x815::m { + enum Data { + V1{x: u64}, + V2{x: u64, y: u8}, + } + } + "#, + ); + assert_success!(result); + + let result = publish( + &mut h, + &acc, + r#" + module 0x815::m2 { + use 0x815::m::Data; + use 0x815::m::S; + fun get_data(): Data { + Data::V1{x: 1} + } + fun pack_struct(): S { + S { x: 22 } + } + } + module 0x815::m { + package enum Data { + V1{x: u64}, + V2{x: u64, y: u8}, + } + + package struct S { + x: u64, + } + } + "#, + ); + assert_success!(result); + + let result = publish( + &mut h, + &acc, + r#" + module 0x815::m2 { + use 0x815::m::Data; + use 0x815::m::S; + use 0x815::m::Predicate; + use 0x815::m::Holder; + fun get_data(): Data { + Data::V1{x: 1} + } + public fun pack_struct(): S { + S { x: 22 } + } + + public fun apply_pred(p: Predicate, val: u64): bool { + p(&val) + } + + public fun apply_holder(h: Holder, val: u64): bool { + let Holder(p) = h; + p(&val) + } + } + module 0x815::m { + public enum Data { + V1{x: u64}, + V2{x: u64, y: u8}, + } + + public struct S { + x: u64, + } + + package struct Predicate(|&T| bool) has copy, drop; + + package struct Holder(Predicate) has copy, drop; + } + "#, + ); + assert_success!(result); +} + +fn publish(h: &mut MoveHarness, account: &Account, source: &str) -> TransactionStatus { + let mut builder = PackageBuilder::new("Package"); + builder.add_source("m.move", source); + let path = builder.write_to_temp().unwrap(); + h.publish_package_with_options( + account, + path.path(), + BuildOptions::move_2().set_latest_language(), + ) +} diff --git a/third_party/move/move-compiler-v2/src/file_format_generator/function_generator.rs b/third_party/move/move-compiler-v2/src/file_format_generator/function_generator.rs index 9bc8b9bdda136..d0606424f3e8f 100644 --- a/third_party/move/move-compiler-v2/src/file_format_generator/function_generator.rs +++ b/third_party/move/move-compiler-v2/src/file_format_generator/function_generator.rs @@ -20,9 +20,12 @@ use move_core_types::{ability, function::ClosureMask}; use move_model::{ ast::{ExpData, Spec, SpecBlockTarget, TempIndex}, exp_rewriter::{ExpRewriter, ExpRewriterFunctions, RewriteTarget}, - model::{FunId, FunctionEnv, Loc, NodeId, Parameter, QualifiedId, StructId, TypeParameter}, + model::{ + FunId, FunctionEnv, Loc, NodeId, Parameter, QualifiedId, StructEnv, StructId, TypeParameter, + }, symbol::Symbol, - ty::{PrimitiveType, Type}, + ty::{PrimitiveType, ReferenceKind, Type}, + well_known, }; use move_stackless_bytecode::{ function_target::FunctionTarget, @@ -196,6 +199,403 @@ impl<'a> FunctionGenerator<'a> { r#gen.module.function_defs.push(def) } + /// Generates test variant api + pub fn gen_struct_test_variant_api<'b>( + r#gen: &'a mut ModuleGenerator, + ctx: &'b ModuleContext, + struct_env: &'b StructEnv<'b>, + ) { + if !struct_env.has_variants() { + return; + } + assert!(struct_env.get_visibility().is_public_or_friend()); + let para_type_parameters = TypeParameter::vec_to_formals(struct_env.get_type_parameters()); + let struct_ty = Type::Struct( + struct_env.module_env.get_id(), + struct_env.get_id(), + para_type_parameters.clone(), + ); + let ref_struct_ty = Type::Reference(ReferenceKind::Immutable, Box::new(struct_ty.clone())); + let loc = struct_env.get_loc(); + let function_indices = r#gen.struct_api_test_variant_index(ctx, &loc, struct_env); + let mut fun_count = r#gen.module.function_defs.len(); + let visibility = struct_env.get_visibility(); + for (variant, function_index) in function_indices { + let def_idx = FunctionDefinitionIndex::new(ctx.checked_bound( + &loc, + fun_count, + MAX_FUNCTION_DEF_COUNT, + "defined function", + )); + r#gen + .source_map + .add_top_level_function_mapping(def_idx, ctx.env.to_ir_loc(&loc), false) + .expect(SOURCE_MAP_OK); + for TypeParameter(name, _, loc) in struct_env.get_type_parameters() { + r#gen + .source_map + .add_function_type_parameter_mapping( + def_idx, + ctx.source_name(name, loc.clone()), + ) + .expect(SOURCE_MAP_OK) + } + let input_para_name = struct_env.env().symbol_pool().make(well_known::PARAM_NAME); + r#gen + .source_map + .add_parameter_mapping(def_idx, ctx.source_name(input_para_name, loc.clone())) + .expect(SOURCE_MAP_OK); + + // Function body: + // MoveLoc(0) + // TestVariant/TestVariantGeneric + // Ret + let locals = r#gen.signature(ctx, &loc, vec![ref_struct_ty.clone()]); + let mut code = vec![]; + code.push(FF::Bytecode::MoveLoc(0 as FF::LocalIndex)); + let test_variant_bc = if para_type_parameters.is_empty() { + let idx = r#gen.struct_variant_index(ctx, &loc, struct_env, variant); + FF::Bytecode::TestVariant(idx) + } else { + let idx = r#gen.struct_variant_inst_index( + ctx, + &loc, + struct_env, + variant, + para_type_parameters.to_vec(), + ); + FF::Bytecode::TestVariantGeneric(idx) + }; + code.push(test_variant_bc); + code.push(FF::Bytecode::Ret); + let code = FF::CodeUnit { locals, code }; + + let def = FF::FunctionDefinition { + function: function_index, + visibility, + is_entry: false, + acquires_global_resources: vec![], + code: Some(code), + }; + + r#gen.module.function_defs.push(def); + fun_count += 1; + } + } + + /// Generates pack api + pub fn gen_struct_pack_api<'b>( + r#gen: &'a mut ModuleGenerator, + ctx: &'b ModuleContext, + struct_env: &'b StructEnv<'b>, + ) { + assert!(struct_env.get_visibility().is_public_or_friend()); + let para_type_parameters = TypeParameter::vec_to_formals(struct_env.get_type_parameters()); + let loc = struct_env.get_loc(); + let function_indices = r#gen.struct_api_pack_index(ctx, &loc, struct_env); + let mut fun_count = r#gen.module.function_defs.len(); + let visibility = struct_env.get_visibility(); + for (variant, function_index) in function_indices { + let def_idx = FunctionDefinitionIndex::new(ctx.checked_bound( + &loc, + fun_count, + MAX_FUNCTION_DEF_COUNT, + "defined function", + )); + r#gen + .source_map + .add_top_level_function_mapping(def_idx, ctx.env.to_ir_loc(&loc), false) + .expect(SOURCE_MAP_OK); + for TypeParameter(name, _, loc) in struct_env.get_type_parameters() { + r#gen + .source_map + .add_function_type_parameter_mapping( + def_idx, + ctx.source_name(name, loc.clone()), + ) + .expect(SOURCE_MAP_OK) + } + + // Function body: + // MoveLoc(0) + // MoveLoc(1) + // ... + // MoveLoc(parameter_count - 1) + // Pack/PackGeneric/PackVariant/PackVariantGeneric + // Ret + let mut tys = vec![]; + let mut code = vec![]; + for (i, field) in struct_env.get_fields_optional_variant(variant).enumerate() { + let field_symbol = struct_env.env().symbol_pool().make(&format!( + "_{}", + field.get_name().display(struct_env.env().symbol_pool()) + )); + r#gen + .source_map + .add_parameter_mapping(def_idx, ctx.source_name(field_symbol, loc.clone())) + .expect(SOURCE_MAP_OK); + code.push(FF::Bytecode::MoveLoc(i as FF::LocalIndex)); + tys.push(field.get_type()); + } + let locals = r#gen.signature(ctx, &loc, tys); + let pack_bc = if para_type_parameters.is_empty() { + if let Some(variant) = variant { + let idx = r#gen.struct_variant_index(ctx, &loc, struct_env, variant); + FF::Bytecode::PackVariant(idx) + } else { + let idx = r#gen.struct_def_index(ctx, &loc, struct_env); + FF::Bytecode::Pack(idx) + } + } else if let Some(variant) = variant { + let idx = r#gen.struct_variant_inst_index( + ctx, + &loc, + struct_env, + variant, + para_type_parameters.to_vec(), + ); + FF::Bytecode::PackVariantGeneric(idx) + } else { + let idx = r#gen.struct_def_instantiation_index( + ctx, + &loc, + struct_env, + para_type_parameters.to_vec(), + ); + FF::Bytecode::PackGeneric(idx) + }; + code.push(pack_bc); + code.push(FF::Bytecode::Ret); + let code = FF::CodeUnit { locals, code }; + + let def = FF::FunctionDefinition { + function: function_index, + visibility, + is_entry: false, + acquires_global_resources: vec![], + code: Some(code), + }; + + r#gen.module.function_defs.push(def); + fun_count += 1; + } + } + + /// Generates unpack api + pub fn gen_struct_unpack_api<'b>( + r#gen: &'a mut ModuleGenerator, + ctx: &'b ModuleContext, + struct_env: &'b StructEnv<'b>, + ) { + assert!(struct_env.get_visibility().is_public_or_friend()); + let para_type_parameters = TypeParameter::vec_to_formals(struct_env.get_type_parameters()); + let loc = struct_env.get_loc(); + let function_indices = r#gen.struct_api_unpack_index(ctx, &loc, struct_env); + let mut fun_count = r#gen.module.function_defs.len(); + let visibility = struct_env.get_visibility(); + let struct_ty = Type::Struct( + struct_env.module_env.get_id(), + struct_env.get_id(), + para_type_parameters.clone(), + ); + for (variant, function_index) in function_indices { + let def_idx = FunctionDefinitionIndex::new(ctx.checked_bound( + &loc, + fun_count, + MAX_FUNCTION_DEF_COUNT, + "defined function", + )); + r#gen + .source_map + .add_top_level_function_mapping(def_idx, ctx.env.to_ir_loc(&loc), false) + .expect(SOURCE_MAP_OK); + for TypeParameter(name, _, loc) in struct_env.get_type_parameters() { + r#gen + .source_map + .add_function_type_parameter_mapping( + def_idx, + ctx.source_name(name, loc.clone()), + ) + .expect(SOURCE_MAP_OK) + } + let input_para_name = struct_env.env().symbol_pool().make(well_known::PARAM_NAME); + r#gen + .source_map + .add_parameter_mapping(def_idx, ctx.source_name(input_para_name, loc.clone())) + .expect(SOURCE_MAP_OK); + + // Function body: + // MoveLoc(0) + // Unpack/UnpackGeneric/UnpackVariant/UnpackVariantGeneric + // Ret + let locals = r#gen.signature(ctx, &loc, vec![struct_ty.clone()]); + let mut code = vec![]; + code.push(FF::Bytecode::MoveLoc(0 as FF::LocalIndex)); + let unpack_bc = if para_type_parameters.is_empty() { + if let Some(variant) = variant { + let idx = r#gen.struct_variant_index(ctx, &loc, struct_env, variant); + FF::Bytecode::UnpackVariant(idx) + } else { + let idx = r#gen.struct_def_index(ctx, &loc, struct_env); + FF::Bytecode::Unpack(idx) + } + } else if let Some(variant) = variant { + let idx = r#gen.struct_variant_inst_index( + ctx, + &loc, + struct_env, + variant, + para_type_parameters.to_vec(), + ); + FF::Bytecode::UnpackVariantGeneric(idx) + } else { + let idx = r#gen.struct_def_instantiation_index( + ctx, + &loc, + struct_env, + para_type_parameters.to_vec(), + ); + FF::Bytecode::UnpackGeneric(idx) + }; + code.push(unpack_bc); + code.push(FF::Bytecode::Ret); + let code = FF::CodeUnit { locals, code }; + + let def = FF::FunctionDefinition { + function: function_index, + visibility, + is_entry: false, + acquires_global_resources: vec![], + code: Some(code), + }; + + r#gen.module.function_defs.push(def); + fun_count += 1; + } + } + + /// Generates borrow field api + pub fn gen_struct_borrow_field_api<'b>( + r#gen: &'a mut ModuleGenerator, + ctx: &'b ModuleContext, + struct_env: &'b StructEnv<'b>, + is_imm: bool, + ) { + assert!(struct_env.get_visibility().is_public_or_friend()); + if struct_env.is_empty_struct() { + return; + } + let para_type_parameters = TypeParameter::vec_to_formals(struct_env.get_type_parameters()); + let loc = struct_env.get_loc(); + let function_indices = r#gen.struct_api_borrow_index(ctx, &loc, struct_env, is_imm); + let mut fun_count = r#gen.module.function_defs.len(); + let visibility = struct_env.get_visibility(); + let struct_ty = Type::Struct( + struct_env.module_env.get_id(), + struct_env.get_id(), + para_type_parameters.clone(), + ); + let ref_struct_ty = Type::Reference( + if is_imm { + ReferenceKind::Immutable + } else { + ReferenceKind::Mutable + }, + Box::new(struct_ty), + ); + for ((variant_opt, offset), function_index) in function_indices { + let def_idx = FunctionDefinitionIndex::new(ctx.checked_bound( + &loc, + fun_count, + MAX_FUNCTION_DEF_COUNT, + "defined function", + )); + r#gen + .source_map + .add_top_level_function_mapping(def_idx, ctx.env.to_ir_loc(&loc), false) + .expect(SOURCE_MAP_OK); + for TypeParameter(name, _, loc) in struct_env.get_type_parameters() { + r#gen + .source_map + .add_function_type_parameter_mapping( + def_idx, + ctx.source_name(name, loc.clone()), + ) + .expect(SOURCE_MAP_OK) + } + let input_para_name = struct_env.env().symbol_pool().make("_s"); + r#gen + .source_map + .add_parameter_mapping(def_idx, ctx.source_name(input_para_name, loc.clone())) + .expect(SOURCE_MAP_OK); + + // Function body: + // MoveLoc(0) + // ImmBorrowField/MutBorrowField/ImmBorrowFieldGeneric/MutBorrowFieldGeneric/ + // ImmBorrowVariantField/MutBorrowVariantField/ImmBorrowVariantFieldGeneric/MutBorrowVariantFieldGeneric + // Ret + let locals = r#gen.signature(ctx, &loc, vec![ref_struct_ty.clone()]); + let mut code = vec![]; + code.push(FF::Bytecode::MoveLoc(0 as FF::LocalIndex)); + let field_env = &struct_env.get_field_by_offset_optional_variant( + variant_opt.clone().map(|variants| variants[0]), + offset, + ); + let borrow_field_bc = if para_type_parameters.is_empty() { + if let Some(variants) = variant_opt { + let idx = r#gen.variant_field_index(ctx, &loc, &variants, field_env); + if is_imm { + FF::Bytecode::ImmBorrowVariantField(idx) + } else { + FF::Bytecode::MutBorrowVariantField(idx) + } + } else { + let idx = r#gen.field_index(ctx, &loc, field_env); + if is_imm { + FF::Bytecode::ImmBorrowField(idx) + } else { + FF::Bytecode::MutBorrowField(idx) + } + } + } else if let Some(variants) = variant_opt { + let idx = r#gen.variant_field_inst_index( + ctx, + &loc, + &variants, + field_env, + para_type_parameters.to_vec(), + ); + if is_imm { + FF::Bytecode::ImmBorrowVariantFieldGeneric(idx) + } else { + FF::Bytecode::MutBorrowVariantFieldGeneric(idx) + } + } else { + let idx = + r#gen.field_inst_index(ctx, &loc, field_env, para_type_parameters.to_vec()); + if is_imm { + FF::Bytecode::ImmBorrowFieldGeneric(idx) + } else { + FF::Bytecode::MutBorrowFieldGeneric(idx) + } + }; + code.push(borrow_field_bc); + code.push(FF::Bytecode::Ret); + let code = FF::CodeUnit { locals, code }; + + let def = FF::FunctionDefinition { + function: function_index, + visibility, + is_entry: false, + acquires_global_resources: vec![], + code: Some(code), + }; + + r#gen.module.function_defs.push(def); + fun_count += 1; + } + } + /// Generates code for a function. fn gen_code(&mut self, ctx: &FunctionContext<'_>) -> FF::CodeUnit { // Initialize the abstract virtual machine @@ -420,62 +820,244 @@ impl<'a> FunctionGenerator<'a> { self.gen_invoke(ctx, dest, source); }, Operation::Pack(mid, sid, inst) => { - self.gen_struct_oper( - ctx, - dest, - mid.qualified(*sid), - inst, - source, - FF::Bytecode::Pack, - FF::Bytecode::PackGeneric, - ); + let fun_mid = ctx.fun_ctx.fun.func_env.module_env.get_id(); + if mid != &fun_mid { + let struct_env = &fun_ctx.module.env.get_struct(mid.qualified(*sid)); + let pack_api_map = self.r#gen.struct_api_pack_index( + &ctx.fun_ctx.module, + &fun_ctx.loc, + struct_env, + ); + // structs does not have variants thus the map size must be 1 + if pack_api_map.len() != 1 { + fun_ctx.internal_error("size of pack api must be 1"); + } + let handle_index = *pack_api_map.values().next().unwrap(); + self.abstract_push_args(ctx, source, None); + if inst.is_empty() { + self.emit(FF::Bytecode::Call(handle_index)); + } else { + let function_instantiation_index = + self.r#gen.function_instantiation_index_from_handle_index( + handle_index, + &ctx.fun_ctx.module, + &fun_ctx.loc, + inst.to_vec(), + ); + self.emit(FF::Bytecode::CallGeneric(function_instantiation_index)); + } + self.abstract_pop_n(ctx, source.len()); + self.abstract_push_result(ctx, dest); + } else { + self.gen_struct_oper( + ctx, + dest, + mid.qualified(*sid), + inst, + source, + FF::Bytecode::Pack, + FF::Bytecode::PackGeneric, + ); + } }, Operation::PackVariant(mid, sid, variant, inst) => { - self.gen_struct_variant_oper( - ctx, - dest, - mid.qualified(*sid), - *variant, - inst, - source, - FF::Bytecode::PackVariant, - FF::Bytecode::PackVariantGeneric, - ); + let struct_env = &fun_ctx.module.env.get_struct(mid.qualified(*sid)); + let fun_mid = ctx.fun_ctx.fun.func_env.module_env.get_id(); + if mid != &fun_mid + && struct_env + .env() + .language_version() + .language_version_for_public_struct() + { + let pack_api_map = self.r#gen.struct_api_pack_index( + &ctx.fun_ctx.module, + &fun_ctx.loc, + struct_env, + ); + if let Some(handle_index) = pack_api_map.get(&Some(*variant)) { + self.abstract_push_args(ctx, source, None); + if inst.is_empty() { + self.emit(FF::Bytecode::Call(*handle_index)); + } else { + let function_instantiation_index = + self.r#gen.function_instantiation_index_from_handle_index( + *handle_index, + &ctx.fun_ctx.module, + &fun_ctx.loc, + inst.to_vec(), + ); + self.emit(FF::Bytecode::CallGeneric(function_instantiation_index)); + } + self.abstract_pop_n(ctx, source.len()); + self.abstract_push_result(ctx, dest); + } else { + fun_ctx.internal_error(format!( + "variant {} not found in pack api map", + variant.display(struct_env.env().symbol_pool()) + )); + } + } else { + self.gen_struct_variant_oper( + ctx, + dest, + mid.qualified(*sid), + *variant, + inst, + source, + FF::Bytecode::PackVariant, + FF::Bytecode::PackVariantGeneric, + ); + } }, Operation::Unpack(mid, sid, inst) => { - self.gen_struct_oper( - ctx, - dest, - mid.qualified(*sid), - inst, - source, - FF::Bytecode::Unpack, - FF::Bytecode::UnpackGeneric, - ); + let struct_env = &fun_ctx.module.env.get_struct(mid.qualified(*sid)); + let fun_mid = ctx.fun_ctx.fun.func_env.module_env.get_id(); + if mid != &fun_mid + && struct_env + .env() + .language_version() + .language_version_for_public_struct() + { + let unpack_api_map = self.r#gen.struct_api_unpack_index( + &ctx.fun_ctx.module, + &fun_ctx.loc, + struct_env, + ); + // structs does not have variants thus the map size must be 1 + if unpack_api_map.len() != 1 { + fun_ctx.internal_error("size of unpack api must be 1"); + } + let handle_index = *unpack_api_map.values().next().unwrap(); + self.abstract_push_args(ctx, source, None); + if inst.is_empty() { + self.emit(FF::Bytecode::Call(handle_index)); + } else { + let function_instantiation_index = + self.r#gen.function_instantiation_index_from_handle_index( + handle_index, + &ctx.fun_ctx.module, + &fun_ctx.loc, + inst.to_vec(), + ); + self.emit(FF::Bytecode::CallGeneric(function_instantiation_index)); + } + self.abstract_pop_n(ctx, source.len()); + self.abstract_push_result(ctx, dest); + } else { + self.gen_struct_oper( + ctx, + dest, + mid.qualified(*sid), + inst, + source, + FF::Bytecode::Unpack, + FF::Bytecode::UnpackGeneric, + ); + } }, Operation::UnpackVariant(mid, sid, variant, inst) => { - self.gen_struct_variant_oper( - ctx, - dest, - mid.qualified(*sid), - *variant, - inst, - source, - FF::Bytecode::UnpackVariant, - FF::Bytecode::UnpackVariantGeneric, - ); + let struct_env = &fun_ctx.module.env.get_struct(mid.qualified(*sid)); + let fun_mid = ctx.fun_ctx.fun.func_env.module_env.get_id(); + if mid != &fun_mid + && struct_env + .env() + .language_version() + .language_version_for_public_struct() + { + let struct_env = &fun_ctx.module.env.get_struct(mid.qualified(*sid)); + let unpack_api_map = self.r#gen.struct_api_unpack_index( + &ctx.fun_ctx.module, + &fun_ctx.loc, + struct_env, + ); + if let Some(handle_index) = unpack_api_map.get(&Some(*variant)) { + self.abstract_push_args(ctx, source, None); + if inst.is_empty() { + self.emit(FF::Bytecode::Call(*handle_index)); + } else { + let function_instantiation_index = + self.r#gen.function_instantiation_index_from_handle_index( + *handle_index, + &ctx.fun_ctx.module, + &fun_ctx.loc, + inst.to_vec(), + ); + self.emit(FF::Bytecode::CallGeneric(function_instantiation_index)); + } + self.abstract_pop_n(ctx, source.len()); + self.abstract_push_result(ctx, dest); + } else { + fun_ctx.internal_error(format!( + "variant {} not found in unpack api map", + variant.display(struct_env.env().symbol_pool()) + )); + } + } else { + self.gen_struct_variant_oper( + ctx, + dest, + mid.qualified(*sid), + *variant, + inst, + source, + FF::Bytecode::UnpackVariant, + FF::Bytecode::UnpackVariantGeneric, + ); + } }, Operation::TestVariant(mid, sid, variant, inst) => { - self.gen_struct_variant_oper( - ctx, - dest, - mid.qualified(*sid), - *variant, - inst, - source, - FF::Bytecode::TestVariant, - FF::Bytecode::TestVariantGeneric, - ); + let struct_env = &fun_ctx.module.env.get_struct(mid.qualified(*sid)); + let fun_mid = ctx.fun_ctx.fun.func_env.module_env.get_id(); + let is_mut_src = fun_ctx.fun.get_local_type(source[0]).is_mutable_reference(); + if mid != &fun_mid + && struct_env + .env() + .language_version() + .language_version_for_public_struct() + { + let test_variant_api_map = self.r#gen.struct_api_test_variant_index( + &ctx.fun_ctx.module, + &fun_ctx.loc, + struct_env, + ); + if let Some(handle_index) = test_variant_api_map.get(variant) { + self.abstract_push_args(ctx, source, None); + // need to freeze mutable ref + if is_mut_src { + self.emit(FF::Bytecode::FreezeRef); + } + if inst.is_empty() { + self.emit(FF::Bytecode::Call(*handle_index)); + } else { + let function_instantiation_index = + self.r#gen.function_instantiation_index_from_handle_index( + *handle_index, + &ctx.fun_ctx.module, + &fun_ctx.loc, + inst.to_vec(), + ); + self.emit(FF::Bytecode::CallGeneric(function_instantiation_index)); + } + self.abstract_pop_n(ctx, source.len()); + self.abstract_push_result(ctx, dest); + } else { + fun_ctx.internal_error(format!( + "variant {} not found in test variant api map", + variant.display(struct_env.env().symbol_pool()) + )); + } + } else { + self.gen_struct_variant_oper( + ctx, + dest, + mid.qualified(*sid), + *variant, + inst, + source, + FF::Bytecode::TestVariant, + FF::Bytecode::TestVariantGeneric, + ); + } }, Operation::MoveTo(mid, sid, inst) => { self.gen_struct_oper( @@ -520,26 +1102,237 @@ impl<'a> FunctionGenerator<'a> { self.abstract_push_result(ctx, dest) }, Operation::BorrowField(mid, sid, inst, offset) => { - self.gen_borrow_field( - ctx, - dest, - mid.qualified(*sid), - inst.clone(), - None, - *offset, - source, - ); + let struct_env = &fun_ctx.module.env.get_struct(mid.qualified(*sid)); + let fun_mid = ctx.fun_ctx.fun.func_env.module_env.get_id(); + let is_mut_dest = fun_ctx.fun.get_local_type(dest[0]).is_mutable_reference(); + let is_mut_src = fun_ctx.fun.get_local_type(source[0]).is_mutable_reference(); + if mid != &fun_mid + && struct_env + .env() + .language_version() + .language_version_for_public_struct() + { + let struct_env = &fun_ctx.module.env.get_struct(mid.qualified(*sid)); + if struct_env.is_empty_struct() { + fun_ctx.internal_error("cannot generate borrow field for empty struct"); + return; + } + let vec = self.r#gen.struct_api_borrow_index( + &ctx.fun_ctx.module, + &fun_ctx.loc, + struct_env, + !is_mut_dest, + ); + let field = struct_env.get_field_by_offset_optional_variant(None, *offset); + let mut found = false; + for ((_, cur_offset), handle_index) in &vec { + if offset == cur_offset { + self.abstract_push_args(ctx, source, None); + // need to freeze mutable ref if the target is an immutable reference + if is_mut_src && !is_mut_dest { + self.emit(FF::Bytecode::FreezeRef); + } + if inst.is_empty() { + self.emit(FF::Bytecode::Call(*handle_index)); + } else { + let function_instantiation_index = + self.r#gen.function_instantiation_index_from_handle_index( + *handle_index, + &ctx.fun_ctx.module, + &fun_ctx.loc, + inst.to_vec(), + ); + self.emit(FF::Bytecode::CallGeneric(function_instantiation_index)); + } + self.abstract_pop_n(ctx, source.len()); + self.abstract_push_result(ctx, dest); + found = true; + break; + } + } + if !found { + fun_ctx.internal_error(format!( + "cannot generate borrow field for the field {} of {} at offset {}", + field.get_name().display(struct_env.env().symbol_pool()), + struct_env.get_full_name_with_address(), + offset + )); + } + } else { + self.gen_borrow_field( + ctx, + dest, + mid.qualified(*sid), + inst.clone(), + None, + *offset, + source, + ); + } }, Operation::BorrowVariantField(mid, sid, variants, inst, offset) => { - self.gen_borrow_field( - ctx, - dest, - mid.qualified(*sid), - inst.clone(), - Some(variants), - *offset, - source, - ); + let struct_env = &fun_ctx.module.env.get_struct(mid.qualified(*sid)); + let fun_mid = ctx.fun_ctx.fun.func_env.module_env.get_id(); + let is_mut_dest = fun_ctx.fun.get_local_type(dest[0]).is_mutable_reference(); + let is_mut_src = fun_ctx.fun.get_local_type(source[0]).is_mutable_reference(); + if mid != &fun_mid + && struct_env + .env() + .language_version() + .language_version_for_public_struct() + { + let struct_env = &fun_ctx.module.env.get_struct(mid.qualified(*sid)); + let vec = self.r#gen.struct_api_borrow_index( + &ctx.fun_ctx.module, + &fun_ctx.loc, + struct_env, + !is_mut_dest, + ); + let mut found = false; + for ((cur_variants_opt, cur_offset), borrow_field_handle_index) in &vec { + if offset == cur_offset { + if let Some(cur_variants) = cur_variants_opt { + if cur_variants == variants { + self.abstract_push_args(ctx, source, None); + // need to freeze mutable ref if the target is an immutable reference + if is_mut_src && !is_mut_dest { + self.emit(FF::Bytecode::FreezeRef); + } + if inst.is_empty() { + self.emit(FF::Bytecode::Call(*borrow_field_handle_index)); + } else { + let function_instantiation_index = self + .r#gen + .function_instantiation_index_from_handle_index( + *borrow_field_handle_index, + &ctx.fun_ctx.module, + &fun_ctx.loc, + inst.to_vec(), + ); + self.emit(FF::Bytecode::CallGeneric( + function_instantiation_index, + )); + } + self.abstract_pop_n(ctx, source.len()); + self.abstract_push_result(ctx, dest); + found = true; + break; + } else if variants.len() == 1 && cur_variants.contains(&variants[0]) + { + let test_variant_api_map = + self.r#gen.struct_api_test_variant_index( + &ctx.fun_ctx.module, + &fun_ctx.loc, + struct_env, + ); + if let Some(test_variant_handle_index) = + test_variant_api_map.get(&variants[0]) + { + // before calling the test variant function, we need to flush the stack + self.abstract_flush_stack_before(ctx, 0); + // call test variant function + self.abstract_push_args( + ctx, + source, + Some(&AssignKind::Copy), + ); + // for test variant, we need to freeze mutable ref if the source is a mutable reference + if is_mut_src { + self.emit(FF::Bytecode::FreezeRef); + } + if inst.is_empty() { + self.emit(FF::Bytecode::Call( + *test_variant_handle_index, + )); + } else { + let function_instantiation_index = self + .r#gen + .function_instantiation_index_from_handle_index( + *test_variant_handle_index, + &ctx.fun_ctx.module, + &fun_ctx.loc, + inst.to_vec(), + ); + self.emit(FF::Bytecode::CallGeneric( + function_instantiation_index, + )); + } + self.abstract_pop_n(ctx, source.len()); + } + let code_offset_after_test_variant = self.code.len(); + + // Block when the test variant fails. + self.code.push(FF::Bytecode::BrTrue( + (code_offset_after_test_variant + 5) as FF::CodeOffset, + )); + let local = self.temp_to_local( + ctx.fun_ctx, + Some(ctx.attr_id), + source[0], + ); + self.code.push(FF::Bytecode::MoveLoc(local)); + self.code.push(FF::Bytecode::Pop); + self.code.push(FF::Bytecode::LdU64( + well_known::INCOMPLETE_MATCH_ABORT_CODE, + )); + self.code.push(FF::Bytecode::Abort); + + // call borrow field api + self.abstract_push_args(ctx, source, None); + // need to freeze mutable ref if the target is an immutable reference + if is_mut_src && !is_mut_dest { + self.emit(FF::Bytecode::FreezeRef); + } + if inst.is_empty() { + self.emit(FF::Bytecode::Call(*borrow_field_handle_index)); + } else { + let function_instantiation_index = self + .r#gen + .function_instantiation_index_from_handle_index( + *borrow_field_handle_index, + &ctx.fun_ctx.module, + &fun_ctx.loc, + inst.to_vec(), + ); + self.emit(FF::Bytecode::CallGeneric( + function_instantiation_index, + )); + } + self.abstract_pop_n(ctx, source.len()); + self.abstract_push_result(ctx, dest); + found = true; + break; + } else if cur_variants.len() == 1 + && variants.contains(&cur_variants[0]) + { + // handle the case e.x where x appears in multiple variants at the same offset but have different or may be instantiated with different types. + struct_env.env().error(&fun_ctx.fun.get_bytecode_loc(ctx.attr_id), &format!("cannot perform borrow operation for field `{}` for struct `{}` since it has or may be instantiated with different types in variants", + struct_env.get_field_by_offset_optional_variant(Some(cur_variants[0]), *offset).get_name().display(struct_env.env().symbol_pool()), + struct_env.get_full_name_with_address())); + found = true; + break; + } + } + } + } + if !found { + fun_ctx.internal_error(format!( + "cannot generate borrow field for {} at offset {}", + struct_env.get_full_name_with_address(), + offset + )); + } + } else { + self.gen_borrow_field( + ctx, + dest, + mid.qualified(*sid), + inst.clone(), + Some(variants), + *offset, + source, + ); + } }, Operation::BorrowGlobal(mid, sid, inst) => { let is_mut = fun_ctx.fun.get_local_type(dest[0]).is_mutable_reference(); diff --git a/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs b/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs index 84def3632b45b..5b62d8c586e04 100644 --- a/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs +++ b/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs @@ -57,6 +57,25 @@ pub struct ModuleGenerator { address_to_idx: BTreeMap, /// A mapping from functions to indices. fun_to_idx: BTreeMap, FF::FunctionHandleIndex>, + /// A mapping from structs to indices of test variant apis. + struct_to_api_test_variant_idx: + BTreeMap, BTreeMap>, + /// A mapping from structs to indices of pack apis. + struct_to_api_pack_idx: + BTreeMap, BTreeMap, FF::FunctionHandleIndex>>, + /// A mapping from structs to indices of unpack apis. + struct_to_api_unpack_idx: + BTreeMap, BTreeMap, FF::FunctionHandleIndex>>, + /// A mapping from structs to indices of immutable borrow field apis. + struct_to_api_imm_borrow_field_idx: BTreeMap< + QualifiedId, + Vec<((Option>, usize), FF::FunctionHandleIndex)>, + >, + /// A mapping from structs to indices of mutable borrow field apis. + struct_to_api_mut_borrow_field_idx: BTreeMap< + QualifiedId, + Vec<((Option>, usize), FF::FunctionHandleIndex)>, + >, /// The special function handle of the `main` function of a script. This is not stored /// in `module.function_handles` because the file format does not maintain a handle /// for this function. @@ -66,6 +85,9 @@ pub struct ModuleGenerator { /// A mapping from function instantiations to indices. fun_inst_to_idx: BTreeMap<(QualifiedId, FF::SignatureIndex), FF::FunctionInstantiationIndex>, + /// A mapping from function handles to instantiation indices. + fun_handle_idx_to_inst_idx: + BTreeMap<(FF::FunctionHandleIndex, FF::SignatureIndex), FF::FunctionInstantiationIndex>, /// A mapping from structs to indices. struct_to_idx: BTreeMap, FF::StructHandleIndex>, /// A mapping from function instantiations to indices. @@ -163,6 +185,11 @@ impl ModuleGenerator { name_to_idx: Default::default(), address_to_idx: Default::default(), fun_to_idx: Default::default(), + struct_to_api_test_variant_idx: Default::default(), + struct_to_api_pack_idx: Default::default(), + struct_to_api_unpack_idx: Default::default(), + struct_to_api_imm_borrow_field_idx: Default::default(), + struct_to_api_mut_borrow_field_idx: Default::default(), struct_to_idx: Default::default(), struct_def_inst_to_idx: Default::default(), field_to_idx: Default::default(), @@ -174,6 +201,7 @@ impl ModuleGenerator { struct_variant_to_idx: Default::default(), struct_variant_inst_to_idx: Default::default(), fun_inst_to_idx: Default::default(), + fun_handle_idx_to_inst_idx: Default::default(), main_handle: None, script_handle: None, module, @@ -200,7 +228,20 @@ impl ModuleGenerator { for struct_env in module_env.get_structs() { assert!(compile_test_code || !struct_env.is_test_only()); - self.gen_struct(ctx, &struct_env) + self.gen_struct(ctx, &struct_env); + // Generate struct apis + if ctx + .env + .language_version() + .language_version_for_public_struct() + && struct_env.get_visibility().is_public_or_friend() + { + FunctionGenerator::gen_struct_test_variant_api(self, ctx, &struct_env); + FunctionGenerator::gen_struct_pack_api(self, ctx, &struct_env); + FunctionGenerator::gen_struct_unpack_api(self, ctx, &struct_env); + FunctionGenerator::gen_struct_borrow_field_api(self, ctx, &struct_env, true); + FunctionGenerator::gen_struct_borrow_field_api(self, ctx, &struct_env, false); + } } let acquires_map = ctx.generate_acquires_map(module_env); @@ -568,6 +609,427 @@ impl ModuleGenerator { idx } + /// Common builder for struct apis + fn build_struct_api_index_common( + &mut self, + ctx: &ModuleContext, + loc: &Loc, + struct_env: &StructEnv, + op_prefix: &str, // e.g., well_known::PACK / UNPACK / TEST_VARIANT + param_sig_index: Option, + return_sig_index: Option, + include_nonvariant_case: bool, // PACK/UNPACK: true; TEST_VARIANT: false + key_conv: fn(Option) -> K, + ) -> BTreeMap { + let module = self.module_index(ctx, loc, &struct_env.module_env); + let struct_full_name = struct_env.get_full_name_with_address(); + let fun_name_prefix = format!( + "{}{}{}", + op_prefix, + well_known::PUBLIC_STRUCT_DELIMITER, + struct_full_name + ) + .replace("::", "$"); + + let type_parameters = struct_env + .get_type_parameters() + .iter() + .map(|TypeParameter(_, TypeParameterKind { abilities, .. }, _)| *abilities) + .collect_vec(); + + let pool = struct_env.env().symbol_pool(); + let cases = if struct_env.has_variants() { + struct_env + .get_variants() + .map(|variant| { + let name = format!( + "{}{}{}", + fun_name_prefix, + well_known::PUBLIC_STRUCT_DELIMITER, + variant.display(pool) + ); + let field_types = struct_env + .get_fields_of_variant(variant) + .map(|f| f.get_type()) + .collect::>(); + (Some(variant), name, field_types) + }) + .collect() + } else if include_nonvariant_case { + let field_types = struct_env + .get_fields() + .map(|f| f.get_type()) + .collect::>(); + vec![(None, fun_name_prefix, field_types)] + } else { + Vec::new() + }; + + let mut result = BTreeMap::new(); + for (variant_opt, name, field_types) in cases { + let params_sig = + param_sig_index.unwrap_or_else(|| self.signature(ctx, loc, field_types.clone())); + let return_sig = + return_sig_index.unwrap_or_else(|| self.signature(ctx, loc, field_types)); + + let idx = FF::FunctionHandleIndex(ctx.checked_bound( + loc, + self.module.function_handles.len(), + MAX_FUNCTION_COUNT, + "used function", + )); + + let name_sym = struct_env.env().symbol_pool().make(&name); + let name_idx = self.name_index(ctx, loc, name_sym); + + let handle = FF::FunctionHandle { + module, + name: name_idx, + type_parameters: type_parameters.clone(), + parameters: params_sig, + return_: return_sig, + access_specifiers: None, + attributes: vec![], + }; + + self.module.function_handles.push(handle); + result.insert(key_conv(variant_opt), idx); + } + + result + } + + /// Generates function handle index for pack api + pub fn struct_api_pack_index( + &mut self, + ctx: &ModuleContext, + loc: &Loc, + struct_env: &StructEnv, + ) -> BTreeMap, FF::FunctionHandleIndex> { + let qid = struct_env.get_qualified_id(); + if let Some(v) = self.struct_to_api_pack_idx.get(&qid) { + return v.clone(); + } + fn id(opt: Option) -> Option { + opt + } + let struct_ty = Type::Struct( + struct_env.module_env.get_id(), + struct_env.get_id(), + TypeParameter::vec_to_formals(struct_env.get_type_parameters()), + ); + let struct_sig = self.signature(ctx, loc, vec![struct_ty]); + let built = self.build_struct_api_index_common( + ctx, + loc, + struct_env, + well_known::PACK, + None, // params = fields + Some(struct_sig), // return = struct + true, // single case if non-variant + id, + ); + self.struct_to_api_pack_idx.insert(qid, built.clone()); + built + } + + /// Generates function handle index for unpack api + pub fn struct_api_unpack_index( + &mut self, + ctx: &ModuleContext, + loc: &Loc, + struct_env: &StructEnv, + ) -> BTreeMap, FF::FunctionHandleIndex> { + let qid = struct_env.get_qualified_id(); + if let Some(v) = self.struct_to_api_unpack_idx.get(&qid) { + return v.clone(); + } + fn id(opt: Option) -> Option { + opt + } + let struct_ty = Type::Struct( + struct_env.module_env.get_id(), + struct_env.get_id(), + TypeParameter::vec_to_formals(struct_env.get_type_parameters()), + ); + let struct_sig = self.signature(ctx, loc, vec![struct_ty]); + let built = self.build_struct_api_index_common( + ctx, + loc, + struct_env, + well_known::UNPACK, + Some(struct_sig), + None, + true, + id, + ); + self.struct_to_api_unpack_idx.insert(qid, built.clone()); + built + } + + /// Generates function handle index for test variant api + pub fn struct_api_test_variant_index( + &mut self, + ctx: &ModuleContext, + loc: &Loc, + struct_env: &StructEnv, + ) -> BTreeMap { + let qid = struct_env.get_qualified_id(); + if let Some(v) = self.struct_to_api_test_variant_idx.get(&qid) { + return v.clone(); + } + fn must_some(opt: Option) -> Symbol { + opt.expect("test_variant key must be a concrete variant") + } + let struct_ty = Type::Struct( + struct_env.module_env.get_id(), + struct_env.get_id(), + TypeParameter::vec_to_formals(struct_env.get_type_parameters()), + ); + let ref_struct_ty = Type::Reference(ReferenceKind::Immutable, Box::new(struct_ty)); + let ref_struct_sig = self.signature(ctx, loc, vec![ref_struct_ty]); + let bool_sig = self.signature(ctx, loc, vec![Type::Primitive(PrimitiveType::Bool)]); + let built = self.build_struct_api_index_common( + ctx, + loc, + struct_env, + well_known::TEST_VARIANT, + Some(ref_struct_sig), + Some(bool_sig), + false, // no function for non-variant structs + must_some, + ); + self.struct_to_api_test_variant_idx + .insert(qid, built.clone()); + built + } + + // Helper function to construct: + // - A mapping from (field name, offset) to (type, variants) when field with the same name and same offset have the same type in variants + // - A mapping from (field name, variant, offset) to type when field with the same name and same offset have different types in variants + fn construct_map_for_borrow_field_api( + struct_env: &StructEnv<'_>, + ) -> ( + BTreeMap<(Symbol, usize), (Type, Vec)>, + BTreeMap<(Symbol, Symbol, usize), Type>, + ) { + let mut field_name_offset_to_variant_map: BTreeMap<(Symbol, usize), (Type, Vec)> = + BTreeMap::new(); + let mut single_field_name_offset_variant_to_ty_map: BTreeMap< + (Symbol, Symbol, usize), + Type, + > = BTreeMap::new(); + let mut single_field_name_offset_pair = Vec::new(); + for variant in struct_env.get_variants() { + for field in struct_env.get_fields_of_variant(variant) { + let ty = field.get_type(); + let offset = field.get_offset(); + let field_name = field.get_name(); + if single_field_name_offset_pair.contains(&(field_name, offset)) { + single_field_name_offset_variant_to_ty_map + .insert((field_name, variant, offset), ty.clone()); + continue; + } + if let std::collections::btree_map::Entry::Vacant(e) = + field_name_offset_to_variant_map.entry((field_name, offset)) + { + let variant_vec = vec![variant]; + e.insert((ty, variant_vec)); + } else if field_name_offset_to_variant_map + .get(&(field_name, offset)) + .unwrap() + .0 + != ty + { + single_field_name_offset_pair.push((field_name, offset)); + while let Some((ty, variant_vec)) = + field_name_offset_to_variant_map.get(&(field_name, offset)) + { + for v in variant_vec { + single_field_name_offset_variant_to_ty_map + .entry((field_name, *v, offset)) + .or_insert_with(|| ty.clone()); + } + field_name_offset_to_variant_map.remove(&(field_name, offset)); + } + single_field_name_offset_variant_to_ty_map + .insert((field_name, variant, offset), ty.clone()); + } else { + let variant_vec: &mut Vec = &mut field_name_offset_to_variant_map + .get_mut(&(field_name, offset)) + .unwrap() + .1; + variant_vec.push(variant); + } + } + } + ( + field_name_offset_to_variant_map, + single_field_name_offset_variant_to_ty_map, + ) + } + + /// Generates function handle index for borrow field api + pub fn struct_api_borrow_index( + &mut self, + ctx: &ModuleContext, + loc: &Loc, + struct_env: &StructEnv, + is_imm: bool, + ) -> Vec<((Option>, usize), FF::FunctionHandleIndex)> { + let module = self.module_index(ctx, loc, &struct_env.module_env); + if is_imm + && self + .struct_to_api_imm_borrow_field_idx + .contains_key(&struct_env.get_qualified_id()) + { + return self + .struct_to_api_imm_borrow_field_idx + .get(&struct_env.get_qualified_id()) + .unwrap() + .clone(); + } + if !is_imm + && self + .struct_to_api_mut_borrow_field_idx + .contains_key(&struct_env.get_qualified_id()) + { + return self + .struct_to_api_mut_borrow_field_idx + .get(&struct_env.get_qualified_id()) + .unwrap() + .clone(); + } + let construct_ref_type = |ty: Type| -> Type { + Type::Reference( + if is_imm { + ReferenceKind::Immutable + } else { + ReferenceKind::Mutable + }, + Box::new(ty), + ) + }; + + let struct_full_name = struct_env.get_full_name_with_address(); + let fun_name_prefix = format!( + "{}{}{}", + if is_imm { + well_known::BORROW_NAME + } else { + well_known::BORROW_MUT_NAME + }, + well_known::PUBLIC_STRUCT_DELIMITER, + struct_full_name + ) + .replace("::", "$"); + let struct_ty = Type::Struct( + struct_env.module_env.get_id(), + struct_env.get_id(), + TypeParameter::vec_to_formals(struct_env.get_type_parameters()), + ); + let ref_struct_ty = construct_ref_type(struct_ty.clone()); + let type_parameters = struct_env + .get_type_parameters() + .iter() + .map(|TypeParameter(_, TypeParameterKind { abilities, .. }, _)| *abilities) + .collect::>(); + let parameters = self.signature(ctx, loc, vec![ref_struct_ty]); + let mut ret = vec![]; + if struct_env.has_variants() { + let (field_name_offset_to_variant_map, standalone_field_name_offset_variant_to_ty_map) = + Self::construct_map_for_borrow_field_api(struct_env); + let mut handle_elements = vec![]; + for ((field_name, offset), (ty, variant_vec)) in field_name_offset_to_variant_map.iter() + { + let return_ = self.signature(ctx, loc, vec![construct_ref_type(ty.clone())]); + let name = format!( + "{}{}{}{}{}", + fun_name_prefix, + well_known::PUBLIC_STRUCT_DELIMITER, + field_name.display(struct_env.env().symbol_pool()), + well_known::PUBLIC_STRUCT_DELIMITER, + offset + ); + handle_elements.push((name, return_, variant_vec.clone(), offset)); + } + for ((field_name, variant, offset), ty) in + standalone_field_name_offset_variant_to_ty_map.iter() + { + let return_ = self.signature(ctx, loc, vec![construct_ref_type(ty.clone())]); + let name = format!( + "{}{}{}{}{}{}{}", + fun_name_prefix, + well_known::PUBLIC_STRUCT_DELIMITER, + field_name.display(struct_env.env().symbol_pool()), + well_known::PUBLIC_STRUCT_DELIMITER, + offset, + well_known::PUBLIC_STRUCT_DELIMITER, + variant.display(struct_env.env().symbol_pool()) + ); + handle_elements.push((name, return_, vec![*variant].clone(), offset)); + } + for (name, return_, variant_vec, offset) in handle_elements { + let handle: FF::FunctionHandle = FF::FunctionHandle { + module, + name: self.name_index(ctx, loc, struct_env.env().symbol_pool().make(&name)), + type_parameters: type_parameters.clone(), + parameters, + return_, + access_specifiers: None, + attributes: vec![], + }; + let idx = FF::FunctionHandleIndex(ctx.checked_bound( + loc, + self.module.function_handles.len(), + MAX_FUNCTION_COUNT, + "used function", + )); + self.module.function_handles.push(handle); + ret.push(((Some(variant_vec), *offset), idx)); + } + } else { + for field in struct_env.get_fields() { + let offset = field.get_offset(); + let ref_type = construct_ref_type(field.get_type()); + let return_ = self.signature(ctx, loc, vec![ref_type]); + let name = format!( + "{}{}{}{}{}", + fun_name_prefix, + well_known::PUBLIC_STRUCT_DELIMITER, + field.get_name().display(struct_env.env().symbol_pool()), + well_known::PUBLIC_STRUCT_DELIMITER, + offset + ); + let idx = FF::FunctionHandleIndex(ctx.checked_bound( + loc, + self.module.function_handles.len(), + MAX_FUNCTION_COUNT, + "used function", + )); + let handle: FF::FunctionHandle = FF::FunctionHandle { + module, + name: self.name_index(ctx, loc, struct_env.env().symbol_pool().make(&name)), + type_parameters: type_parameters.clone(), + parameters, + return_, + access_specifiers: None, + attributes: vec![], + }; + self.module.function_handles.push(handle); + ret.push(((None, offset), idx)); + } + } + if is_imm { + self.struct_to_api_imm_borrow_field_idx + .insert(struct_env.get_qualified_id(), ret.clone()); + } else { + self.struct_to_api_mut_borrow_field_idx + .insert(struct_env.get_qualified_id(), ret.clone()); + } + ret + } + pub fn access_specifier( &mut self, ctx: &ModuleContext, @@ -675,6 +1137,40 @@ impl ModuleGenerator { idx } + // Obtains or generates instantiation index from handle index and type parameters + pub fn function_instantiation_index_from_handle_index( + &mut self, + handle: FF::FunctionHandleIndex, + ctx: &ModuleContext, + loc: &Loc, + inst: Vec, + ) -> FF::FunctionInstantiationIndex { + let type_parameters = self.signature(ctx, loc, inst); + let fun_inst = FF::FunctionInstantiation { + handle, + type_parameters, + }; + if self + .fun_handle_idx_to_inst_idx + .contains_key(&(handle, type_parameters)) + { + return *self + .fun_handle_idx_to_inst_idx + .get(&(handle, type_parameters)) + .unwrap(); + } + let idx = FF::FunctionInstantiationIndex(ctx.checked_bound( + loc, + self.module.function_instantiations.len(), + MAX_FUNCTION_INST_COUNT, + "function instantiation", + )); + self.module.function_instantiations.push(fun_inst); + self.fun_handle_idx_to_inst_idx + .insert((handle, type_parameters), idx); + idx + } + /// Obtains or generates a struct index. pub fn struct_index( &mut self, diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/bug_16222_fv_wrapper_unpack.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/bug_16222_fv_wrapper_unpack.exp index 9a5ce7b338b86..9289f44488db8 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/bug_16222_fv_wrapper_unpack.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/bug_16222_fv_wrapper_unpack.exp @@ -223,19 +223,112 @@ public fun n::test_friend() { } -Diagnostics: -bug: compiler internal error: struct not defined - ┌─ tests/bytecode-generator/bug_16222_fv_wrapper_unpack.move:20:16 - │ -20 │ public fun test() { - │ ^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) - -bug: compiler internal error: struct not defined - ┌─ tests/bytecode-generator/bug_16222_fv_wrapper_unpack.move:25:16 - │ -25 │ public fun test_friend() { - │ ^^^^^^^^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) +============ disassembled file-format ================== +// Bytecode version v9 +module 0xc0ffee::m +friend 0xc0ffee::n +struct Lazy has drop + _0: || has drop + +// Function definition at index 0 +friend fun pack$0xc0ffee$m$Lazy(l0: || has drop): Lazy + local l1: || has drop + move_loc l0 + pack Lazy + ret + +// Function definition at index 1 +friend fun unpack$0xc0ffee$m$Lazy(l0: Lazy): || has drop + local l1: Lazy + move_loc l0 + unpack Lazy + ret + +// Function definition at index 2 +friend fun borrow$0xc0ffee$m$Lazy$0$0(l0: &Lazy): &|| has drop + local l1: &Lazy + move_loc l0 + borrow_field Lazy, _0 + ret + +// Function definition at index 3 +friend fun borrow_mut$0xc0ffee$m$Lazy$0$0(l0: &mut Lazy): &mut || has drop + local l1: &mut Lazy + move_loc l0 + mut_borrow_field Lazy, _0 + ret + +// Function definition at index 4 +#[persistent] public fun make_lazy(): Lazy + pack_closure __lambda__1__make_lazy, 0 + pack Lazy + ret + +// Function definition at index 5 +fun __lambda__1__make_lazy() + ret + +// Bytecode version v9 +module 0xc0ffee::m_friend +friend 0xc0ffee::n +struct Lazy has drop + _0: || has drop + +// Function definition at index 0 +friend fun pack$0xc0ffee$m_friend$Lazy(l0: || has drop): Lazy + local l1: || has drop + move_loc l0 + pack Lazy + ret + +// Function definition at index 1 +friend fun unpack$0xc0ffee$m_friend$Lazy(l0: Lazy): || has drop + local l1: Lazy + move_loc l0 + unpack Lazy + ret + +// Function definition at index 2 +friend fun borrow$0xc0ffee$m_friend$Lazy$0$0(l0: &Lazy): &|| has drop + local l1: &Lazy + move_loc l0 + borrow_field Lazy, _0 + ret + +// Function definition at index 3 +friend fun borrow_mut$0xc0ffee$m_friend$Lazy$0$0(l0: &mut Lazy): &mut || has drop + local l1: &mut Lazy + move_loc l0 + mut_borrow_field Lazy, _0 + ret + +// Function definition at index 4 +#[persistent] public fun make_lazy(): Lazy + pack_closure __lambda__1__make_lazy, 0 + pack Lazy + ret + +// Function definition at index 5 +fun __lambda__1__make_lazy() + ret + +// Bytecode version v9 +module 0xc0ffee::n +use 0xc0ffee::m +use 0xc0ffee::m_friend +// Function definition at index 0 +#[persistent] public fun test() + call m::make_lazy + call m::unpack$0xc0ffee$m$Lazy + call_closure <|| has drop> + ret + +// Function definition at index 1 +#[persistent] public fun test_friend() + call m_friend::make_lazy + call m_friend::unpack$0xc0ffee$m_friend$Lazy + call_closure <|| has drop> + ret + + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/bug_16543_fv_wrapper_pack.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/bug_16543_fv_wrapper_pack.exp index add1b7ece87d8..5d5e80fa97623 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/bug_16543_fv_wrapper_pack.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/bug_16543_fv_wrapper_pack.exp @@ -143,19 +143,98 @@ fun n::__lambda__1__test_friend() { } -Diagnostics: -bug: compiler internal error: struct not defined - ┌─ tests/bytecode-generator/bug_16543_fv_wrapper_pack.move:13:16 - │ -13 │ public fun test(): 0xc0ffee::m::Lazy { - │ ^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) - -bug: compiler internal error: struct not defined - ┌─ tests/bytecode-generator/bug_16543_fv_wrapper_pack.move:17:16 - │ -17 │ public fun test_friend(): 0xc0ffee::m_friend::Lazy { - │ ^^^^^^^^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) +============ disassembled file-format ================== +// Bytecode version v9 +module 0xc0ffee::m +friend 0xc0ffee::n +struct Lazy has drop + _0: || has drop + +// Function definition at index 0 +friend fun pack$0xc0ffee$m$Lazy(l0: || has drop): Lazy + local l1: || has drop + move_loc l0 + pack Lazy + ret + +// Function definition at index 1 +friend fun unpack$0xc0ffee$m$Lazy(l0: Lazy): || has drop + local l1: Lazy + move_loc l0 + unpack Lazy + ret + +// Function definition at index 2 +friend fun borrow$0xc0ffee$m$Lazy$0$0(l0: &Lazy): &|| has drop + local l1: &Lazy + move_loc l0 + borrow_field Lazy, _0 + ret + +// Function definition at index 3 +friend fun borrow_mut$0xc0ffee$m$Lazy$0$0(l0: &mut Lazy): &mut || has drop + local l1: &mut Lazy + move_loc l0 + mut_borrow_field Lazy, _0 + ret + +// Bytecode version v9 +module 0xc0ffee::m_friend +friend 0xc0ffee::n +struct Lazy has drop + _0: || has drop + +// Function definition at index 0 +friend fun pack$0xc0ffee$m_friend$Lazy(l0: || has drop): Lazy + local l1: || has drop + move_loc l0 + pack Lazy + ret + +// Function definition at index 1 +friend fun unpack$0xc0ffee$m_friend$Lazy(l0: Lazy): || has drop + local l1: Lazy + move_loc l0 + unpack Lazy + ret + +// Function definition at index 2 +friend fun borrow$0xc0ffee$m_friend$Lazy$0$0(l0: &Lazy): &|| has drop + local l1: &Lazy + move_loc l0 + borrow_field Lazy, _0 + ret + +// Function definition at index 3 +friend fun borrow_mut$0xc0ffee$m_friend$Lazy$0$0(l0: &mut Lazy): &mut || has drop + local l1: &mut Lazy + move_loc l0 + mut_borrow_field Lazy, _0 + ret + +// Bytecode version v9 +module 0xc0ffee::n +use 0xc0ffee::m +use 0xc0ffee::m_friend +// Function definition at index 0 +#[persistent] public fun test(): m::Lazy + pack_closure __lambda__1__test, 0 + call m::pack$0xc0ffee$m$Lazy + ret + +// Function definition at index 1 +#[persistent] public fun test_friend(): m_friend::Lazy + pack_closure __lambda__1__test_friend, 0 + call m_friend::pack$0xc0ffee$m_friend$Lazy + ret + +// Function definition at index 2 +fun __lambda__1__test() + ret + +// Function definition at index 3 +fun __lambda__1__test_friend() + ret + + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/checking-lang-v2.4/cross_module_borrow_field_err.exp b/third_party/move/move-compiler-v2/tests/checking-lang-v2.4/cross_module_borrow_field_err.exp index c3a08c0b97b19..637c0eb96626d 100644 --- a/third_party/move/move-compiler-v2/tests/checking-lang-v2.4/cross_module_borrow_field_err.exp +++ b/third_party/move/move-compiler-v2/tests/checking-lang-v2.4/cross_module_borrow_field_err.exp @@ -446,19 +446,225 @@ fun n::test_no_err() { } -Diagnostics: -bug: compiler internal error: struct not defined - ┌─ tests/checking-lang-v2.4/cross_module_borrow_field_err.move:16:9 - │ -16 │ fun test_1() { - │ ^^^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) +============ disassembled file-format ================== +// Bytecode version v9 +module 0xc0ffee::m +enum Wrapper has drop + V1 + _0: u64 + _1: u64 + V2 + _0: u64 + +// Function definition at index 0 +public fun test_variant$0xc0ffee$m$Wrapper$V1(l0: &Wrapper): bool + local l1: &Wrapper + move_loc l0 + test_variant Wrapper, V1 + ret + +// Function definition at index 1 +public fun test_variant$0xc0ffee$m$Wrapper$V2(l0: &Wrapper): bool + local l1: &Wrapper + move_loc l0 + test_variant Wrapper, V2 + ret + +// Function definition at index 2 +public fun pack$0xc0ffee$m$Wrapper$V1(l0: u64, l1: u64): Wrapper + local l2: u64 + local l3: u64 + move_loc l0 + move_loc l1 + pack_variant Wrapper, V1 + ret + +// Function definition at index 3 +public fun pack$0xc0ffee$m$Wrapper$V2(l0: u64): Wrapper + local l1: u64 + move_loc l0 + pack_variant Wrapper, V2 + ret + +// Function definition at index 4 +public fun unpack$0xc0ffee$m$Wrapper$V1(l0: Wrapper): (u64, u64) + local l1: Wrapper + move_loc l0 + unpack_variant Wrapper, V1 + ret + +// Function definition at index 5 +public fun unpack$0xc0ffee$m$Wrapper$V2(l0: Wrapper): u64 + local l1: Wrapper + move_loc l0 + unpack_variant Wrapper, V2 + ret + +// Function definition at index 6 +public fun borrow$0xc0ffee$m$Wrapper$0$0(l0: &Wrapper): &u64 + local l1: &Wrapper + move_loc l0 + borrow_variant_field Wrapper, V1::_0, V2::_0 + ret + +// Function definition at index 7 +public fun borrow$0xc0ffee$m$Wrapper$1$1(l0: &Wrapper): &u64 + local l1: &Wrapper + move_loc l0 + borrow_variant_field Wrapper, V1::_1 + ret -bug: compiler internal error: struct not defined - ┌─ tests/checking-lang-v2.4/cross_module_borrow_field_err.move:41:9 +// Function definition at index 8 +public fun borrow_mut$0xc0ffee$m$Wrapper$0$0(l0: &mut Wrapper): &mut u64 + local l1: &mut Wrapper + move_loc l0 + mut_borrow_variant_field Wrapper, V1::_0, V2::_0 + ret + +// Function definition at index 9 +public fun borrow_mut$0xc0ffee$m$Wrapper$1$1(l0: &mut Wrapper): &mut u64 + local l1: &mut Wrapper + move_loc l0 + mut_borrow_variant_field Wrapper, V1::_1 + ret + +// Function definition at index 10 +#[persistent] public fun make(l0: u64): Wrapper + copy_loc l0 + move_loc l0 + ld_u64 1 + add + pack_variant Wrapper, V1 + // @5 + ret + +// Bytecode version v9 +module 0xc0ffee::n +use 0xc0ffee::m +// Function definition at index 0 +fun foo(l0: &mut u64, l1: &mut u64) + move_loc l0 + pop + move_loc l1 + pop + ret + +// Function definition at index 1 +fun test_1() + local l0: m::Wrapper + local l1: &mut u64 + local l2: &mut u64 + ld_u64 22 + call m::make + st_loc l0 + mut_borrow_loc l0 + call m::borrow_mut$0xc0ffee$m$Wrapper$0$0 + // @5 + mut_borrow_loc l0 + call m::borrow_mut$0xc0ffee$m$Wrapper$1$1 + call foo + ret + +// Function definition at index 2 +fun test_2() + local l0: m::Wrapper + local l1: u64 + local l2: &mut u64 + local l3: &mut u64 + ld_u64 22 + call m::make + st_loc l0 + mut_borrow_loc l0 + call m::borrow_mut$0xc0ffee$m$Wrapper$0$0 + // @5 + mut_borrow_loc l0 + call m::borrow_mut$0xc0ffee$m$Wrapper$1$1 + st_loc l2 + st_loc l3 + ld_u64 23 + // @10 + move_loc l3 + write_ref + ld_u64 24 + move_loc l2 + write_ref + // @15 + ret + +// Function definition at index 3 +fun test_match() + local l0: m::Wrapper + local l1: &mut m::Wrapper + local l2: &mut u64 + local l3: &mut u64 + ld_u64 22 + call m::make + st_loc l0 + mut_borrow_loc l0 + st_loc l1 + // @5 + copy_loc l1 + freeze_ref + call m::test_variant$0xc0ffee$m$Wrapper$V2 + br_false l0 + move_loc l1 + // @10 + pop + ret +l0: copy_loc l1 + freeze_ref + call m::test_variant$0xc0ffee$m$Wrapper$V1 + // @15 + br_false l1 + copy_loc l1 + freeze_ref + call m::test_variant$0xc0ffee$m$Wrapper$V1 + br_true l2 + // @20 + move_loc l1 + pop + ld_u64 14566554180833181697 + abort +l2: copy_loc l1 + // @25 + call m::borrow_mut$0xc0ffee$m$Wrapper$0$0 + move_loc l1 + call m::borrow_mut$0xc0ffee$m$Wrapper$1$1 + call foo + ret + // @30 +l1: move_loc l1 + pop + ld_u64 14566554180833181697 + abort + +// Function definition at index 4 +fun test_no_err() + local l0: m::Wrapper + ld_u64 22 + call m::make + st_loc l0 + ld_u64 23 + mut_borrow_loc l0 + // @5 + call m::borrow_mut$0xc0ffee$m$Wrapper$0$0 + write_ref + ld_u64 24 + mut_borrow_loc l0 + call m::borrow_mut$0xc0ffee$m$Wrapper$1$1 + // @10 + write_ref + ret + + +============ bytecode verification failed ======== + +Diagnostics: +bug: bytecode verification failed with unexpected status code `CALL_BORROWED_MUTABLE_REFERENCE_ERROR`: +Error message: none + ┌─ tests/checking-lang-v2.4/cross_module_borrow_field_err.move:19:19 │ -41 │ fun test_match() { - │ ^^^^^^^^^^ +19 │ let x_1 = &mut x.1; + │ ^^^^^^^^ │ = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) diff --git a/third_party/move/move-compiler-v2/tests/checking-lang-v2.4/cross_module_package_access_success.exp b/third_party/move/move-compiler-v2/tests/checking-lang-v2.4/cross_module_package_access_success.exp index 350541125395f..cb57c80b6c8ef 100644 --- a/third_party/move/move-compiler-v2/tests/checking-lang-v2.4/cross_module_package_access_success.exp +++ b/third_party/move/move-compiler-v2/tests/checking-lang-v2.4/cross_module_package_access_success.exp @@ -1,5 +1,8 @@ // -- Model dump before first bytecode pipeline module 0xc0ffee::m { + struct Empty { + dummy_field: bool, + } struct S { x: u64, } @@ -140,6 +143,8 @@ module 0xc0ffee::m { friend 0xc0ffee::n7; friend 0xc0ffee::n8; friend 0xc0ffee::n9; + struct Empty { + } struct S { x: u64, } @@ -399,6 +404,9 @@ fun n_friend::test_pack_friend_struct(): 0xc0ffee::m_friend::T { // -- Model dump before second bytecode pipeline module 0xc0ffee::m { + struct Empty { + dummy_field: bool, + } struct S { x: u64, } @@ -676,83 +684,351 @@ fun n_friend::test_pack_friend_struct(): 0xc0ffee::m_friend::T { } -Diagnostics: -bug: compiler internal error: struct not defined - ┌─ tests/checking-lang-v2.4/cross_module_package_access_success.move:35:9 - │ -35 │ fun test() { - │ ^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) - -bug: compiler internal error: struct not defined - ┌─ tests/checking-lang-v2.4/cross_module_package_access_success.move:44:9 - │ -44 │ fun test_pack() { - │ ^^^^^^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) - -bug: compiler internal error: struct not defined - ┌─ tests/checking-lang-v2.4/cross_module_package_access_success.move:52:9 - │ -52 │ fun test_unpack(w: Wrapper) { - │ ^^^^^^^^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) - -bug: compiler internal error: struct not defined - ┌─ tests/checking-lang-v2.4/cross_module_package_access_success.move:60:9 - │ -60 │ fun test_select_variant(w: Wrapper): u64 { - │ ^^^^^^^^^^^^^^^^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) - -bug: compiler internal error: struct not defined - ┌─ tests/checking-lang-v2.4/cross_module_package_access_success.move:68:9 - │ -68 │ fun test_test_variant(w: Wrapper): bool { - │ ^^^^^^^^^^^^^^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) - -bug: compiler internal error: struct not defined - ┌─ tests/checking-lang-v2.4/cross_module_package_access_success.move:76:9 - │ -76 │ fun test_match(w: Wrapper): bool { - │ ^^^^^^^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) - -bug: compiler internal error: struct not defined - ┌─ tests/checking-lang-v2.4/cross_module_package_access_success.move:87:9 - │ -87 │ fun test_pack_struct(): S { - │ ^^^^^^^^^^^^^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) - -bug: compiler internal error: struct not defined - ┌─ tests/checking-lang-v2.4/cross_module_package_access_success.move:95:9 - │ -95 │ fun test_pack_friend_struct(): T { - │ ^^^^^^^^^^^^^^^^^^^^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) - -bug: compiler internal error: struct not defined - ┌─ tests/checking-lang-v2.4/cross_module_package_access_success.move:107:9 - │ -107 │ fun test_pack_struct(): S { - │ ^^^^^^^^^^^^^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) - -bug: compiler internal error: struct not defined - ┌─ tests/checking-lang-v2.4/cross_module_package_access_success.move:120:9 - │ -120 │ fun test_pack_unpack_struct_in_lambda() { - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ - = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) +============ disassembled file-format ================== +// Bytecode version v9 +module 0xc0ffee::m +friend 0xc0ffee::n +friend 0xc0ffee::n2 +friend 0xc0ffee::n3 +friend 0xc0ffee::n4 +friend 0xc0ffee::n5 +friend 0xc0ffee::n6 +friend 0xc0ffee::n7 +friend 0xc0ffee::n8 +friend 0xc0ffee::n9 +struct Empty + dummy_field: bool + +struct S + x: u64 + +struct S2 + x: u64 + s: S + +enum Wrapper has drop + V1 + _0: u64 + V2 + _0: u64 + +// Function definition at index 0 +friend fun pack$0xc0ffee$m$Empty(l0: bool): Empty + local l1: bool + move_loc l0 + pack Empty + ret + +// Function definition at index 1 +friend fun unpack$0xc0ffee$m$Empty(l0: Empty): bool + local l1: Empty + move_loc l0 + unpack Empty + ret + +// Function definition at index 2 +friend fun pack$0xc0ffee$m$S(l0: u64): S + local l1: u64 + move_loc l0 + pack S + ret + +// Function definition at index 3 +friend fun unpack$0xc0ffee$m$S(l0: S): u64 + local l1: S + move_loc l0 + unpack S + ret + +// Function definition at index 4 +friend fun borrow$0xc0ffee$m$S$x$0(l0: &S): &u64 + local l1: &S + move_loc l0 + borrow_field S, x + ret + +// Function definition at index 5 +friend fun borrow_mut$0xc0ffee$m$S$x$0(l0: &mut S): &mut u64 + local l1: &mut S + move_loc l0 + mut_borrow_field S, x + ret + +// Function definition at index 6 +friend fun pack$0xc0ffee$m$S2(l0: u64, l1: S): S2 + local l2: u64 + local l3: S + move_loc l0 + move_loc l1 + pack S2 + ret + +// Function definition at index 7 +friend fun unpack$0xc0ffee$m$S2(l0: S2): (u64, S) + local l1: S2 + move_loc l0 + unpack S2 + ret + +// Function definition at index 8 +friend fun borrow$0xc0ffee$m$S2$x$0(l0: &S2): &u64 + local l1: &S2 + move_loc l0 + borrow_field S2, x + ret + +// Function definition at index 9 +friend fun borrow$0xc0ffee$m$S2$s$1(l0: &S2): &S + local l1: &S2 + move_loc l0 + borrow_field S2, s + ret + +// Function definition at index 10 +friend fun borrow_mut$0xc0ffee$m$S2$x$0(l0: &mut S2): &mut u64 + local l1: &mut S2 + move_loc l0 + mut_borrow_field S2, x + ret + +// Function definition at index 11 +friend fun borrow_mut$0xc0ffee$m$S2$s$1(l0: &mut S2): &mut S + local l1: &mut S2 + move_loc l0 + mut_borrow_field S2, s + ret + +// Function definition at index 12 +friend fun test_variant$0xc0ffee$m$Wrapper$V1(l0: &Wrapper): bool + local l1: &Wrapper + move_loc l0 + test_variant Wrapper, V1 + ret + +// Function definition at index 13 +friend fun test_variant$0xc0ffee$m$Wrapper$V2(l0: &Wrapper): bool + local l1: &Wrapper + move_loc l0 + test_variant Wrapper, V2 + ret + +// Function definition at index 14 +friend fun pack$0xc0ffee$m$Wrapper$V1(l0: u64): Wrapper + local l1: u64 + move_loc l0 + pack_variant Wrapper, V1 + ret + +// Function definition at index 15 +friend fun pack$0xc0ffee$m$Wrapper$V2(l0: u64): Wrapper + local l1: u64 + move_loc l0 + pack_variant Wrapper, V2 + ret + +// Function definition at index 16 +friend fun unpack$0xc0ffee$m$Wrapper$V1(l0: Wrapper): u64 + local l1: Wrapper + move_loc l0 + unpack_variant Wrapper, V1 + ret + +// Function definition at index 17 +friend fun unpack$0xc0ffee$m$Wrapper$V2(l0: Wrapper): u64 + local l1: Wrapper + move_loc l0 + unpack_variant Wrapper, V2 + ret + +// Function definition at index 18 +friend fun borrow$0xc0ffee$m$Wrapper$0$0(l0: &Wrapper): &u64 + local l1: &Wrapper + move_loc l0 + borrow_variant_field Wrapper, V1::_0, V2::_0 + ret + +// Function definition at index 19 +friend fun borrow_mut$0xc0ffee$m$Wrapper$0$0(l0: &mut Wrapper): &mut u64 + local l1: &mut Wrapper + move_loc l0 + mut_borrow_variant_field Wrapper, V1::_0, V2::_0 + ret + +// Function definition at index 20 +#[persistent] public fun make(l0: u64): Wrapper + move_loc l0 + pack_variant Wrapper, V1 + ret + +// Bytecode version v9 +module 0xc0ffee::m_friend +friend 0xc0ffee::n_friend +struct T + x: u64 + +// Function definition at index 0 +friend fun pack$0xc0ffee$m_friend$T(l0: u64): T + local l1: u64 + move_loc l0 + pack T + ret + +// Function definition at index 1 +friend fun unpack$0xc0ffee$m_friend$T(l0: T): u64 + local l1: T + move_loc l0 + unpack T + ret + +// Function definition at index 2 +friend fun borrow$0xc0ffee$m_friend$T$x$0(l0: &T): &u64 + local l1: &T + move_loc l0 + borrow_field T, x + ret + +// Function definition at index 3 +friend fun borrow_mut$0xc0ffee$m_friend$T$x$0(l0: &mut T): &mut u64 + local l1: &mut T + move_loc l0 + mut_borrow_field T, x + ret + +// Bytecode version v9 +module 0xc0ffee::n +use 0xc0ffee::m +// Function definition at index 0 +fun test() + local l0: m::Wrapper + ld_u64 22 + call m::make + st_loc l0 + borrow_loc l0 + call m::borrow$0xc0ffee$m$Wrapper$0$0 + // @5 + read_ref + ld_u64 22 + eq + br_false l0 + ret + // @10 +l0: ld_u64 1 + abort + +// Bytecode version v9 +module 0xc0ffee::n2 +use 0xc0ffee::m +// Function definition at index 0 +fun test_pack() + ld_u64 22 + call m::pack$0xc0ffee$m$Wrapper$V1 + pop + ret + +// Bytecode version v9 +module 0xc0ffee::n3 +use 0xc0ffee::m +// Function definition at index 0 +fun test_unpack(l0: m::Wrapper) + move_loc l0 + call m::unpack$0xc0ffee$m$Wrapper$V1 + pop + ret + +// Bytecode version v9 +module 0xc0ffee::n4 +use 0xc0ffee::m +// Function definition at index 0 +fun test_select_variant(l0: m::Wrapper): u64 + borrow_loc l0 + call m::borrow$0xc0ffee$m$Wrapper$0$0 + read_ref + ret + +// Bytecode version v9 +module 0xc0ffee::n5 +use 0xc0ffee::m +// Function definition at index 0 +fun test_test_variant(l0: m::Wrapper): bool + borrow_loc l0 + call m::test_variant$0xc0ffee$m$Wrapper$V1 + ret + +// Bytecode version v9 +module 0xc0ffee::n6 +use 0xc0ffee::m +// Function definition at index 0 +fun test_match(l0: m::Wrapper): bool + local l1: &m::Wrapper + borrow_loc l0 + st_loc l1 + copy_loc l1 + call m::test_variant$0xc0ffee$m$Wrapper$V1 + br_false l0 + // @5 + move_loc l1 + pop + move_loc l0 + call m::unpack$0xc0ffee$m$Wrapper$V1 + pop + // @10 + ld_true + ret +l0: move_loc l1 + call m::test_variant$0xc0ffee$m$Wrapper$V2 + br_false l1 + // @15 + move_loc l0 + call m::unpack$0xc0ffee$m$Wrapper$V2 + pop + ld_false + ret + // @20 +l1: ld_u64 14566554180833181697 + abort + +// Bytecode version v9 +module 0xc0ffee::n7 +use 0xc0ffee::m +// Function definition at index 0 +fun test_pack_struct(): m::S + ld_u64 22 + call m::pack$0xc0ffee$m$S + ret + +// Bytecode version v9 +module 0xc0ffee::n8 +use 0xc0ffee::m +// Function definition at index 0 +fun test_pack_struct(): m::S + ld_u64 22 + call m::pack$0xc0ffee$m$S + ret + +// Bytecode version v9 +module 0xc0ffee::n9 +use 0xc0ffee::m +// Function definition at index 0 +fun test_pack_unpack_struct_in_lambda() + ld_u64 22 + ld_u64 33 + call m::pack$0xc0ffee$m$S + call m::pack$0xc0ffee$m$S2 + call m::unpack$0xc0ffee$m$S2 + // @5 + call m::unpack$0xc0ffee$m$S + pop + pop + ret + +// Bytecode version v9 +module 0xc0ffee::n_friend +use 0xc0ffee::m_friend +// Function definition at index 0 +fun test_pack_friend_struct(): m_friend::T + ld_u64 22 + call m_friend::pack$0xc0ffee$m_friend$T + ret + + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/checking-lang-v2.4/cross_module_package_access_success.move b/third_party/move/move-compiler-v2/tests/checking-lang-v2.4/cross_module_package_access_success.move index 32547880759f1..37bcf795e8698 100644 --- a/third_party/move/move-compiler-v2/tests/checking-lang-v2.4/cross_module_package_access_success.move +++ b/third_party/move/move-compiler-v2/tests/checking-lang-v2.4/cross_module_package_access_success.move @@ -18,6 +18,8 @@ module 0xc0ffee::m { s: S, } + public(package) struct Empty {} + } module 0xc0ffee::m_friend { diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_assign_field.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_assign_field.exp new file mode 100644 index 0000000000000..0402210987acc --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_assign_field.exp @@ -0,0 +1,84 @@ +processed 9 tasks +task 0 lines 1-18: publish [module 0x42::test {] +task 1 lines 20-130: publish [module 0x42::test_assign_field {] +Error: compilation errors: + bug: bytecode verification failed with unexpected status code `CALL_BORROWED_MUTABLE_REFERENCE_ERROR`: +Error message: none + ┌─ TEMPFILE1:61:13 + │ +61 │ E::V1(x, y) => { + │ ^^^^^^^^^^^ + │ + = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) + + +task 2 lines 132-132: run --verbose -- 0x42::test_assign_field::test_simple +Error: Function execution failed with VMError: { + message: Linker Error: Module 0000000000000000000000000000000000000000000000000000000000000042::test_assign_field doesn't exist, + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], + exec_state: None, +} +task 3 lines 134-134: run --verbose -- 0x42::test_assign_field::test_simple_ref +Error: Function execution failed with VMError: { + message: Linker Error: Module 0000000000000000000000000000000000000000000000000000000000000042::test_assign_field doesn't exist, + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], + exec_state: None, +} +task 4 lines 136-136: run --verbose -- 0x42::test_assign_field::test_assign0 +Error: Function execution failed with VMError: { + message: Linker Error: Module 0000000000000000000000000000000000000000000000000000000000000042::test_assign_field doesn't exist, + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], + exec_state: None, +} +task 5 lines 138-138: run --verbose -- 0x42::test_assign_field::test_assign1 +Error: Function execution failed with VMError: { + message: Linker Error: Module 0000000000000000000000000000000000000000000000000000000000000042::test_assign_field doesn't exist, + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], + exec_state: None, +} +task 6 lines 140-140: run --verbose -- 0x42::test_assign_field::test_assign_chained +Error: Function execution failed with VMError: { + message: Linker Error: Module 0000000000000000000000000000000000000000000000000000000000000042::test_assign_field doesn't exist, + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], + exec_state: None, +} +task 7 lines 142-142: run --verbose -- 0x42::test_assign_field::test_assign_enum_1 +Error: Function execution failed with VMError: { + message: Linker Error: Module 0000000000000000000000000000000000000000000000000000000000000042::test_assign_field doesn't exist, + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], + exec_state: None, +} +task 8 lines 144-144: run --verbose -- 0x42::test_assign_field::test_assign_enum_2 +Error: Function execution failed with VMError: { + message: Linker Error: Module 0000000000000000000000000000000000000000000000000000000000000042::test_assign_field doesn't exist, + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], + exec_state: None, +} diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_assign_field.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_assign_field.move new file mode 100644 index 0000000000000..2574e699f1953 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_assign_field.move @@ -0,0 +1,144 @@ +//# publish +module 0x42::test { + public struct S0 has copy, drop { + x: u8, + } + + public struct S1(u64, bool) has drop; + + public struct S2(S0, u8) has copy, drop; + + public struct S3(S2, S0, S2) has drop; + + public enum E has drop { + V1(u8, bool), + V2(S3), + } + +} + +//# publish +module 0x42::test_assign_field { + use 0x42::test::S0; + use 0x42::test::S1; + use 0x42::test::S2; + use 0x42::test::S3; + use 0x42::test::E; + + fun simple(x: S1): S1 { + x.0 = 42; + x.1 = true; + x + } + + fun simple_ref(x: &mut S1) { + x.0 = 42; + x.1 = true; + } + + fun assign0(a: u64, b: bool): S1 { + let x = S1(a, b); + while (x.1) { + x = S1(x.0 - 1, x.0 >= 2); + }; + x + } + + fun assign1(x: S1): u64 { + let count = 0; + while (x.1) { + let y = if (x.0 > 0) { x.0 - 1 } else { 0 }; + x = S1(y, y >=1); + count = count + 1; + }; + count + } + + fun assign_chained(x: S3): S3 { + x.0.0.x + x.1.x + x.2.0.x; + x.0.0.x = 0; + x.1.x = 1; + x.2.0.x = 2; + x + } + + fun assign_enum(x: &mut E) { + match (x) { + E::V1(x, y) => { + *x = 42; + *y = true; + }, + E::V2(x) => { + x.0.0.x = 0; + x.1.x = 1; + x.2.0.x = 2; + } + } + } + + fun test_simple(): S1 { + let x = S1(0, false); + let y = simple(x); + y + } + + fun test_simple_ref(): S1 { + let x = S1(0, false); + simple_ref(&mut x); + x + } + + fun test_assign0(): S1 { + assign0(4, true) + } + + fun test_assign1(): u64 { + let x = S1(4, true); + assign1(x) + } + + fun test_assign_chained(): S3 { + let x0 = S0 { x: 42 }; + let x1 = S2(x0, 42); + let x2 = S3(x1, x0, x1); + x2 = assign_chained(x2); + x2 + } + + fun test_assign_enum_1(): bool { + let x0 = S0 { x: 43 }; + let x1 = S2(x0, 42); + let x2 = S3(x1, x0, x1); + let x3 = E::V2(x2); + assign_enum(&mut x3); + let y0 = S0 { x: 0 }; + let y1 = S0 { x: 1 }; + let y2 = S0 { x: 2 }; + let y3 = S2(y0, 42); + let y4 = S2(y2, 42); + let y5 = S3(y3, y1, y4); + let y6 = E::V2(y5); + x3 == y6 + } + + fun test_assign_enum_2(): bool { + let x = E::V1(0, false); + assign_enum(&mut x); + let y = E::V1(42, true); + x == y + } +} + +//# run --verbose -- 0x42::test_assign_field::test_simple + +//# run --verbose -- 0x42::test_assign_field::test_simple_ref + +//# run --verbose -- 0x42::test_assign_field::test_assign0 + +//# run --verbose -- 0x42::test_assign_field::test_assign1 + +//# run --verbose -- 0x42::test_assign_field::test_assign_chained + +//# run --verbose -- 0x42::test_assign_field::test_assign_enum_1 + +//# run --verbose -- 0x42::test_assign_field::test_assign_enum_2 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_assign_unpack_references.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_assign_unpack_references.exp new file mode 100644 index 0000000000000..3799b749e0c22 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_assign_unpack_references.exp @@ -0,0 +1,30 @@ +processed 4 tasks +task 0 lines 1-7: publish [module 0x42::m {] +task 1 lines 9-34: publish [module 0x42::m2 {] +Error: compilation errors: + bug: bytecode verification failed with unexpected status code `CALL_BORROWED_MUTABLE_REFERENCE_ERROR`: +Error message: none + ┌─ TEMPFILE1:23:9 + │ +23 │ R { s1: S { f }, s2 } = &mut R { s1: S{f: 0}, s2: S{f: 1} }; f; s2; + │ ^^^^^^^^^^^^^^^^^^^^^ + │ + = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) + + +task 2 lines 36-36: run 0x42::m2::t1 +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 3 lines 38-38: run 0x42::m2::t2 +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_assign_unpack_references.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_assign_unpack_references.move new file mode 100644 index 0000000000000..8e813126f4572 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_assign_unpack_references.move @@ -0,0 +1,38 @@ +//# publish +module 0x42::m { + public struct S has drop{ f: u64 } + public struct R has drop{ s1: S, s2: S } + + +} + +//# publish +module 0x42::m2 { + use 0x42::m::R; + use 0x42::m::S; + + fun t1() { + let f; + let s2; + R { s1: S { f }, s2 } = &R { s1: S{f: 0}, s2: S{f: 1} }; + assert!(*f == 0, 0); + assert!(s2.f == 1, 1); + } + + fun t2() { + let f; + let s2; + R { s1: S { f }, s2 } = &mut R { s1: S{f: 0}, s2: S{f: 1} }; f; s2; + assert!(*f == 0, 0); + assert!(s2.f == 1, 1); + f = &mut 5; + s2 = &mut S { f: 0 }; + assert!(*f == 5, 0); + assert!(s2.f == 0, 1); + } + +} + +//# run 0x42::m2::t1 + +//# run 0x42::m2::t2 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_calls_with_freeze.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_calls_with_freeze.exp new file mode 100644 index 0000000000000..a7eb3ff3b4a22 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_calls_with_freeze.exp @@ -0,0 +1,5 @@ +processed 3 tasks +task 0 lines 1-4: publish [module 0x42::m {] +task 1 lines 6-25: publish [module 0x42::m_calls_with_freeze {] +task 2 lines 27-27: run 0x42::m_calls_with_freeze::test +return values: 16 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_calls_with_freeze.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_calls_with_freeze.move new file mode 100644 index 0000000000000..a354c03aa2312 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_calls_with_freeze.move @@ -0,0 +1,27 @@ +//# publish +module 0x42::m { + public struct S has drop { x: u64 } +} + +//# publish +module 0x42::m_calls_with_freeze { + use 0x42::m::S; + + fun sum(s: &S, other: &S): u64 { s.x + other.x } + + fun test_arg_freeze(s: S) : u64 { + let p1m = &mut s; + let s2 = S { x: 4 }; + let p2m = &mut s2; + let x1 = sum(p1m, p2m); + let x2 = sum(p1m, p1m); + let x3 = sum(&s, p2m); + x1 + x2 + x3 + } + + fun test(): u64 { + test_arg_freeze(S{x: 2}) + } +} + +//# run 0x42::m_calls_with_freeze::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_capturing.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_capturing.exp new file mode 100644 index 0000000000000..6ac079d09b42c --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_capturing.exp @@ -0,0 +1,9 @@ +processed 5 tasks +task 0 lines 1-6: publish [module 0x42::test {] +task 1 lines 8-30: publish [module 0x42::test_capturing {] +task 2 lines 32-32: run 0x42::test_capturing::one_captured --args 3 +return values: 5 +task 3 lines 34-34: run 0x42::test_capturing::two_captured --args 3 2u8 +return values: 8 +task 4 lines 36-36: run 0x42::test_capturing::struct_captured --args 3 +return values: 7 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_capturing.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_capturing.move new file mode 100644 index 0000000000000..43daf0114d98b --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_capturing.move @@ -0,0 +1,36 @@ +//# publish +module 0x42::test { + public struct S has drop, copy { + f: u64 + } +} + +//# publish +module 0x42::test_capturing { + use 0x42::test::S; + + public fun one_captured(x: u64): u64 { + let f = |y| x + y; + f(2) + } + + public fun two_captured(x: u64, y: u8): u64 { + let f = |z| x + (y as u64) + z; + f(3) + } + + public fun struct_captured(f: u64): u64 { + struct_captured_helper(S { f }) + } + + fun struct_captured_helper(s: S): u64 { + let f = |x| s.f + x; + f(4) + } +} + +//# run 0x42::test_capturing::one_captured --args 3 + +//# run 0x42::test_capturing::two_captured --args 3 2u8 + +//# run 0x42::test_capturing::struct_captured --args 3 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_capturing_generic.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_capturing_generic.exp new file mode 100644 index 0000000000000..024e411380d10 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_capturing_generic.exp @@ -0,0 +1,7 @@ +processed 4 tasks +task 0 lines 1-8: publish [module 0x42::test {] +task 1 lines 10-26: publish [module 0x42::test_capturing_generic {] +task 2 lines 28-28: run 0x42::test_capturing_generic::test_u64 --args 3 +return values: false +task 3 lines 30-30: run 0x42::test_capturing_generic::test_S --args 2 +return values: true diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_capturing_generic.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_capturing_generic.move new file mode 100644 index 0000000000000..c9e746373f674 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_capturing_generic.move @@ -0,0 +1,30 @@ +//# publish +module 0x42::test { + public struct S has drop, copy { + f: u64 + } + + +} + +//# publish +module 0x42::test_capturing_generic { + use 0x42::test::S; + + fun eq_with(x: T): |T| bool { + |y| x == y + } + + public fun test_u64(x: u64): bool { + eq_with(2)(x) + } + + public fun test_S(x: u64): bool { + eq_with(S{f:2})(S{f: x}) + } + +} + +//# run 0x42::test_capturing_generic::test_u64 --args 3 + +//# run 0x42::test_capturing_generic::test_S --args 2 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_closures_in_enums.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_closures_in_enums.exp new file mode 100644 index 0000000000000..8547ea8713008 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_closures_in_enums.exp @@ -0,0 +1,7 @@ +processed 6 tasks +task 0 lines 1-8: publish [module 0xc0ffee::m {] +task 1 lines 10-115: publish [module 0xc0ffee::m_closures_in_enums {] +task 2 lines 117-117: run 0xc0ffee::m_closures_in_enums::test_1 +task 3 lines 119-119: run 0xc0ffee::m_closures_in_enums::test_2 +task 4 lines 121-121: run 0xc0ffee::m_closures_in_enums::test_3 +task 5 lines 123-123: run 0xc0ffee::m_closures_in_enums::test_4 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_closures_in_enums.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_closures_in_enums.move new file mode 100644 index 0000000000000..6930488ccb77b --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_closures_in_enums.move @@ -0,0 +1,123 @@ +//# publish +module 0xc0ffee::m { + public enum Function has copy, drop { + NoParam(||u64), + OneParam(|u64|u64), + TwoParam(|u64, u64|u64), + } +} + +//# publish +module 0xc0ffee::m_closures_in_enums { + use 0xc0ffee::m::Function; + + fun runner_1(f: Function): u64 { + match (f) { + Function::NoParam(func) => func(), + Function::OneParam(func) => func(0), + Function::TwoParam(func) => func(0, 0), + } + } + + public fun test_1() { + let f1 = Function::NoParam(|| 0); + assert!(runner_1(f1) == 0); + + let f2 = Function::OneParam(|x| x); + assert!(runner_1(f2) == 0); + + let f3 = Function::TwoParam(|x, y| x + y); + assert!(runner_1(f3) == 0); + + let x = 1; + let f4 = Function::NoParam(|| x); + assert!(runner_1(f4) == 1); + + let x = 1; + let f5 = Function::OneParam(|y| x + y); + assert!(runner_1(f5) == 1); + } + + fun runner_2(f: Function): u64 { + let to_call = match (f) { + Function::NoParam(func) => func, + Function::OneParam(func) => || func(0), + Function::TwoParam(func) => || func(0, 0), + }; + to_call() + } + + public fun test_2() { + let f1 = Function::NoParam(|| 0); + assert!(runner_2(f1) == 0); + + let f2 = Function::OneParam(|x| x); + assert!(runner_2(f2) == 0); + + let f3 = Function::TwoParam(|x, y| x + y); + assert!(runner_2(f3) == 0); + + let x = 1; + let f4 = Function::NoParam(|| x); + assert!(runner_2(f4) == 1); + + let x = 1; + let f5 = Function::OneParam(|y| x + y); + assert!(runner_2(f5) == 1); + } + + fun get_func(f: &Function): &||u64 has copy { + match (f) { + Function::NoParam(func) => func, + _ => abort 42 + } + } + + fun runner_3(f: &Function): u64 { + (*get_func(f))() + } + + fun test_3() { + let f1 = Function::NoParam(|| 0); + assert!(runner_3(&f1) == 0); + } + + fun get_func_recursive(f: Function): ||u64 { + match (f) { + Function::NoParam(func) => func, + Function::OneParam(func) => get_func_recursive(Function::NoParam(||func(0))), + Function::TwoParam(func) => get_func_recursive(Function::OneParam(|x|func(0, x))), + } + } + + fun runner_4(f: Function): u64 { + get_func_recursive(f)() + } + + public fun test_4() { + let f1 = Function::NoParam(|| 0); + assert!(runner_4(f1) == 0); + + let f2 = Function::OneParam(|x| x); + assert!(runner_4(f2) == 0); + + let f3 = Function::TwoParam(|x, y| x + y); + assert!(runner_4(f3) == 0); + + let x = 1; + let f4 = Function::NoParam(|| x); + assert!(runner_4(f4) == 1); + + let x = 1; + let f5 = Function::OneParam(|y| x + y); + assert!(runner_4(f5) == 1); + } +} + +//# run 0xc0ffee::m_closures_in_enums::test_1 + +//# run 0xc0ffee::m_closures_in_enums::test_2 + +//# run 0xc0ffee::m_closures_in_enums::test_3 + +//# run 0xc0ffee::m_closures_in_enums::test_4 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_common_access.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_common_access.exp new file mode 100644 index 0000000000000..fcd2952e72e84 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_common_access.exp @@ -0,0 +1,5 @@ +processed 3 tasks +task 0 lines 1-7: publish [module 0x42::test {] +task 1 lines 9-21: publish [module 0x42::test_common_access {] +task 2 lines 23-23: run --verbose -- 0x42::test_common_access::test_common_access +return values: 42 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_common_access.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_common_access.move new file mode 100644 index 0000000000000..a8024e19bfe90 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_common_access.move @@ -0,0 +1,23 @@ +//# publish +module 0x42::test { + public enum Foo has drop { + A(u8), + B(u8), + } +} + +//# publish +module 0x42::test_common_access { + use 0x42::test::Foo; + + fun common_access(x: Foo): u8 { + x.0 + } + + fun test_common_access(): u8 { + let x = Foo::A(42); + common_access(x) + } +} + +//# run --verbose -- 0x42::test_common_access::test_common_access diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_conditional_borrow.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_conditional_borrow.exp new file mode 100644 index 0000000000000..d2be7823e428e --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_conditional_borrow.exp @@ -0,0 +1,5 @@ +processed 3 tasks +task 0 lines 1-6: publish [module 0x8675::M {] +task 1 lines 8-33: publish [module 0x8675::test_M {] +task 2 lines 35-35: run 0x8675::test_M::testb +return values: 11 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_conditional_borrow.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_conditional_borrow.move new file mode 100644 index 0000000000000..f5cd51eba6851 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_conditional_borrow.move @@ -0,0 +1,35 @@ +//# publish +module 0x8675::M { + public struct S has copy, drop { + f: u64 + } +} + +//# publish +module 0x8675::test_M { + use 0x8675::M::S; + fun test1b(r: S): u64 { // 7 or 2 + let x = S { f: 3 }; + let tref = &mut { if (r.f < 4) { r } else { x } }; // &mut tmp = 7 or 3 + (*tref).f = 10; // ignored, writes to *&tmp + let y = r; // 7 or 2 + let tref2 = &mut y; + (*tref2).f = (*tref2).f + 1; // y = 8 or 3 + let z = y; // 8 or 3 + let tref3 = &mut z.f; + (*tref3) = (*tref3) + 1; // ignored, writes to temp + let a = z; // 8 or 3 + let tref4 = &mut { let _q = 1; a.f }; + (*tref4) = (*tref4) + 1; // ignored, writes to temp + let tref5 = &mut { a.f }; + *tref5 = *tref5 + 8; // ignored, writes to temp + let tref6 = &mut { 3; a.f }; + *tref6 = *tref6 + 16; // ignored, writes to temp + a.f // 8 or 3 + } + public fun testb(): u64 { + test1b(S{ f: 7 }) + test1b(S{ f: 2 }) // 11 + } +} + +//# run 0x8675::test_M::testb diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_consume_1.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_consume_1.exp new file mode 100644 index 0000000000000..667c7ed18a7bb --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_consume_1.exp @@ -0,0 +1,6 @@ +processed 5 tasks +task 0 lines 1-7: publish [module 0xc0ffee::m {] +task 1 lines 9-47: publish [module 0xc0ffee::test_m {] +task 2 lines 49-49: run 0xc0ffee::test_m::test1 --args 42 +task 3 lines 51-51: run 0xc0ffee::test_m::test2 --args 42 +task 4 lines 53-53: run 0xc0ffee::test_m::test5 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_consume_1.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_consume_1.move new file mode 100644 index 0000000000000..c14bdec726ebb --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_consume_1.move @@ -0,0 +1,53 @@ +//# publish +module 0xc0ffee::m { + + public struct W has copy, drop { + x: u64, + } +} + +//# publish +module 0xc0ffee::test_m { + use 0xc0ffee::m::W; + + fun consume(_x: u64) {} + + public fun test1(x: u64) { + let y = x; + consume(x); + consume(y); + } + + public fun test2(x: u64) { + let y = x; + consume(y); + consume(x); + } + + fun consume_(_x: W) {} + + public fun test3(x: W) { + let y = x; + consume_(x); + consume_(y); + } + + public fun test4(x: W) { + let y = x; + consume_(y); + consume_(x); + } + + public fun test5() { + let x = W { x: 42 }; + let y = copy x; + test3(x); + test4(y); + } +} + +//# run 0xc0ffee::test_m::test1 --args 42 + +//# run 0xc0ffee::test_m::test2 --args 42 + +//# run 0xc0ffee::test_m::test5 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_exhaustive_check.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_exhaustive_check.exp new file mode 100644 index 0000000000000..85c6eab655e21 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_exhaustive_check.exp @@ -0,0 +1,3 @@ +processed 2 tasks +task 0 lines 1-18: publish [module 0x42::test {] +task 1 lines 20-31: publish [module 0x42::test_bug_14296 {] diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_exhaustive_check.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_exhaustive_check.move new file mode 100644 index 0000000000000..292c5d011c4a7 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_exhaustive_check.move @@ -0,0 +1,31 @@ +//# publish +module 0x42::test { + public struct S0 has drop {} + + public struct S1 has drop { + x: A, + y: B + } + + public enum E has drop { + V1{ x: u8, y: S1}, + V2 { + x: u8, + y: S0 + } + } + +} + +//# publish +module 0x42::test_bug_14296 { + use 0x42::test::E; + use 0x42::test::S1; + + fun extract_last_u8(y: &E): u8 { + match (y) { + E::V1{ x: _, y: S1 { x, y: _}} => *x, + E::V2 { y: _, x: _ } => 1, + } + } +} diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_field_select.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_field_select.move new file mode 100644 index 0000000000000..b6b5638d82639 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_field_select.move @@ -0,0 +1,49 @@ +//# publish +module 0x42::m { + + public enum Data has drop { + V1{x: u64}, + V2{x: u64, y: bool} + } + +} + +//# publish +module 0x42::test_m { + use 0x42::m::Data; + + fun test_get_x_v1(): u64 { + let d = Data::V1{x: 43}; + d.x + } + + fun test_get_x_v2(): u64 { + let d = Data::V2{x: 43, y: false}; + d.x + } + + fun test_get_y_v1(): bool { + let d = Data::V1{x: 43}; + get_y(&d) + } + + fun get_y(d: &Data): bool { + match (d) { + V2{x: _, y} => *y, + _ => abort 33 + } + } + + fun test_get_y_v2(): bool { + let d = Data::V2{x: 43, y: true}; + get_y(&d) + } +} + +//# run 0x42::test_m::test_get_x_v1 + +//# run 0x42::test_m::test_get_x_v2 + +//# run 0x42::test_m::test_get_y_v1 + +//# run 0x42::test_m::test_get_y_v2 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_field_select.public-struct.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_field_select.public-struct.exp new file mode 100644 index 0000000000000..4f25ff4b733c6 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_field_select.public-struct.exp @@ -0,0 +1,17 @@ +processed 6 tasks +task 0 lines 1-9: publish [module 0x42::m {] +task 1 lines 11-41: publish [module 0x42::test_m {] +task 2 lines 43-43: run 0x42::test_m::test_get_x_v1 +return values: 43 +task 3 lines 45-45: run 0x42::test_m::test_get_x_v2 +return values: 43 +task 4 lines 47-47: run 0x42::test_m::test_get_y_v1 +Error: Function execution failed with VMError: { + major_status: ABORTED, + sub_status: Some(33), + location: 0x42::test_m, + indices: [], + offsets: [(FunctionDefinitionIndex(0), 10)], +} +task 5 lines 49-49: run 0x42::test_m::test_get_y_v2 +return values: true diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_field_select_different_offsets.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_field_select_different_offsets.exp new file mode 100644 index 0000000000000..de125536169d9 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_field_select_different_offsets.exp @@ -0,0 +1,27 @@ +processed 8 tasks +task 0 lines 1-10: publish [module 0x42::m {] +task 1 lines 12-46: publish [module 0x42::test_m {] +task 2 lines 48-48: run 0x42::test_m::test_get_x_v1 +return values: 43 +task 3 lines 50-50: run 0x42::test_m::test_get_x_v2 +return values: 43 +task 4 lines 52-52: run 0x42::test_m::test_get_x_v3 +return values: 43 +task 5 lines 54-54: run 0x42::test_m::test_get_y_v1 +Error: Function execution failed with VMError: { + major_status: STRUCT_VARIANT_MISMATCH, + sub_status: None, + location: 0x42::m, + indices: [], + offsets: [(FunctionDefinitionIndex(11), 1)], +} +task 6 lines 56-56: run 0x42::test_m::test_get_y_v2 +return values: true +task 7 lines 58-58: run 0x42::test_m::test_get_y_v3 +Error: Function execution failed with VMError: { + major_status: STRUCT_VARIANT_MISMATCH, + sub_status: None, + location: 0x42::m, + indices: [], + offsets: [(FunctionDefinitionIndex(11), 1)], +} diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_field_select_different_offsets.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_field_select_different_offsets.move new file mode 100644 index 0000000000000..262f328d21324 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_field_select_different_offsets.move @@ -0,0 +1,58 @@ +//# publish +module 0x42::m { + + public enum Data has drop { + V1{x: u64}, + V2{y: bool, x: u64} + V3{z: u8, x: u64} + } + +} + +//# publish +module 0x42::test_m { + use 0x42::m::Data; + + fun test_get_x_v1(): u64 { + let d = Data::V1{x: 43}; + d.x + } + + fun test_get_x_v2(): u64 { + let d = Data::V2{x: 43, y: false}; + d.x + } + + fun test_get_x_v3(): u64 { + let d = Data::V3{z: 1, x: 43}; + d.x + } + + fun test_get_y_v1(): bool { + let d = Data::V1{x: 43}; + d.y + } + + fun test_get_y_v2(): bool { + let d = Data::V2{x: 43, y: true}; + d.y + } + + fun test_get_y_v3(): bool { + let d = Data::V3{x: 43, z: 1}; + d.y + } + +} + +//# run 0x42::test_m::test_get_x_v1 + +//# run 0x42::test_m::test_get_x_v2 + +//# run 0x42::test_m::test_get_x_v3 + +//# run 0x42::test_m::test_get_y_v1 + +//# run 0x42::test_m::test_get_y_v2 + +//# run 0x42::test_m::test_get_y_v3 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_matching.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_matching.exp new file mode 100644 index 0000000000000..243a49c9c00a7 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_matching.exp @@ -0,0 +1,31 @@ +processed 16 tasks +task 0 lines 1-30: publish [module 0x42::m {] +task 1 lines 32-184: publish [module 0x42::test_m {] +task 2 lines 186-186: run 0x42::test_m::t1_is_inner1 +return values: true +task 3 lines 188-188: run 0x42::test_m::t2_is_inner1 +return values: false +task 4 lines 190-190: run 0x42::test_m::t1_inner_value +return values: 7 +task 5 lines 192-192: run 0x42::test_m::t1_outer_value +return values: 0 +task 6 lines 194-194: run 0x42::test_m::t2_outer_value +return values: 3 +task 7 lines 196-196: run 0x42::test_m::t3_outer_value +return values: 8 +task 8 lines 198-198: run 0x42::test_m::t1_outer_value_nested +return values: 27 +task 9 lines 200-200: run 0x42::test_m::t2_outer_value_nested +return values: 12 +task 10 lines 202-202: run 0x42::test_m::t1_outer_value_with_cond +return values: 1 +task 11 lines 204-204: run 0x42::test_m::t1_outer_value_with_cond_ref +return values: true +task 12 lines 206-206: run 0x42::test_m::t1_is_some +return values: false +task 13 lines 208-208: run 0x42::test_m::t2_is_some +return values: true +task 14 lines 210-210: run 0x42::test_m::t1_is_some_specialized +return values: false +task 15 lines 212-212: run 0x42::test_m::t2_is_some_specialized +return values: true diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_matching.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_matching.move new file mode 100644 index 0000000000000..056e6de18329c --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_matching.move @@ -0,0 +1,212 @@ +//# publish +module 0x42::m { + + public enum Inner has drop { + Inner1{ x: u64 } + Inner2{ x: u64, y: u64 } + } + + public struct Box has drop { + x: u64 + } + + public enum Outer has drop { + None, + One{i: Inner}, + Two{i: Inner, b: Box}, + } + + /// Matching with abilities and generics + public enum Option has drop { + None, + Some{value: A} + } + + // Common fields + public enum CommonFields { + Foo{x: u64, y: u64}, + Bar{z: u64, x: u64} + } +} + +//# publish +module 0x42::test_m { + use 0x42::m::Inner; + use 0x42::m::Box; + use 0x42::m::Outer; + use 0x42::m::Option; + use 0x42::m::CommonFields; + + /// Simple matching + public fun inner_value(i: Inner): u64 { + match (i) { + Inner1{x} => x, + Inner2{x, y} => x + y + } + } + + /// Matching with wildcard and reference + public fun is_inner1(i: &Inner): bool { + match (i) { + Inner1{x: _} => true, + _ => false + } + } + + /// Matching which delegates ownership + public fun outer_value(o: Outer): u64 { + match (o) { + None => 0, + // `i` is moved and consumed by `inner_value` + One{i} => inner_value(i), + Two{i, b} => inner_value(i) + b.x + } + } + + /// Nested matching with delegation + public fun outer_value_nested(o: Outer): u64 { + match (o) { + None => 0, + // Nested match will require multiple probing steps + One{i: Inner::Inner1{x}} => x, + One{i} => inner_value(i), + Two{i, b} => inner_value(i) + b.x + } + } + + /// Matching with condition + public fun outer_value_with_cond(o: Outer): u64 { + match (o) { + None => 0, + // Match with condition requires probing and conversion from 'Deref(Borrow(x))` to `x`. + One{i} if is_inner1(&i) => inner_value(i) % 2, + One{i} => inner_value(i), + Two{i, b} => inner_value(i) + b.x + } + } + + /// Matching with condition with references and wildcard + public fun outer_value_with_cond_ref(o: &Outer): bool { + match (o) { + None => false, + One{i} if is_inner1(i) => true, + One{i} => is_inner1(i), + Two{i, b: _} => is_inner1(i) + } + } + + + public fun is_some(x: &Option): bool { + match (x) { + None => false, + Some{value: _} => true + } + } + + public fun is_some_specialized(x: &Option>): bool { + match (x) { + None => false, + Some{value: Option::None} => false, + Some{value: Option::Some{value: _}} => true, + } + } + + public fun is_some_dropped(x: Option): bool { + match (x) { + None => false, + _ => true + } + } + + + fun select_common_fields(s: CommonFields): u64 { + s.x + (match (s) { Foo{x: _, y} => y, Bar{z, x: _} => z }) + } + + // ------------------- + // Test entry points + + fun t1_is_inner1(): bool { + is_inner1(&Inner::Inner1{x: 2}) + } + + fun t2_is_inner1(): bool { + is_inner1(&Inner::Inner2{x: 2, y: 3}) + } + + fun t1_inner_value(): u64 { + inner_value(Inner::Inner2{x: 2, y: 5}) + } + + fun t1_outer_value(): u64 { + outer_value(Outer::None{}) + } + + fun t2_outer_value(): u64 { + outer_value(Outer::One{i: Inner::Inner2{x: 1, y: 2}}) + } + + fun t3_outer_value(): u64 { + outer_value(Outer::Two{i: Inner::Inner1{x: 1}, b: Box{x: 7}}) + } + + fun t1_outer_value_nested(): u64 { + outer_value_nested(Outer::One{i: Inner::Inner1{x: 27}}) + } + + fun t2_outer_value_nested(): u64 { + outer_value_nested(Outer::Two{i: Inner::Inner1{x: 5}, b: Box{x: 7}}) + } + + fun t1_outer_value_with_cond(): u64 { + outer_value_with_cond(Outer::One{i: Inner::Inner1{x: 43}}) + } + + fun t1_outer_value_with_cond_ref(): bool { + outer_value_with_cond_ref(&Outer::One{i: Inner::Inner1{x: 43}}) + } + + fun t1_is_some(): bool { + is_some(&Option::None{}) + } + + fun t2_is_some(): bool { + is_some(&Option::Some{value: 3}) + } + + fun t1_is_some_specialized(): bool { + is_some_specialized(&Option::Some{value: Option::None{}}) + } + + fun t2_is_some_specialized(): bool { + is_some_specialized(&Option::Some{value: Option::Some{value: 1}}) + } +} + +//# run 0x42::test_m::t1_is_inner1 + +//# run 0x42::test_m::t2_is_inner1 + +//# run 0x42::test_m::t1_inner_value + +//# run 0x42::test_m::t1_outer_value + +//# run 0x42::test_m::t2_outer_value + +//# run 0x42::test_m::t3_outer_value + +//# run 0x42::test_m::t1_outer_value_nested + +//# run 0x42::test_m::t2_outer_value_nested + +//# run 0x42::test_m::t1_outer_value_with_cond + +//# run 0x42::test_m::t1_outer_value_with_cond_ref + +//# run 0x42::test_m::t1_is_some + +//# run 0x42::test_m::t2_is_some + +//# run 0x42::test_m::t1_is_some_specialized + +//# run 0x42::test_m::t2_is_some_specialized diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_scoping.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_scoping.exp new file mode 100644 index 0000000000000..f5a0b4c7f2e53 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_scoping.exp @@ -0,0 +1,24 @@ +processed 3 tasks +task 0 lines 1-19: publish [module 0x42::m {] +task 1 lines 21-50: publish [module 0x42::test_m {] +warning: This assignment/binding to the left-hand-side variable `x` is unused. Consider removing this assignment/binding, or prefixing the left-hand-side variable with an underscore (e.g., `_x`), or renaming to `_` + ┌─ TEMPFILE1:30:21 + │ +30 │ let x = 4; + │ ^ + +warning: This assignment/binding to the left-hand-side variable `b` is unused. Consider removing this assignment/binding, or prefixing the left-hand-side variable with an underscore (e.g., `_b`), or renaming to `_` + ┌─ TEMPFILE1:45:13 + │ +45 │ Two{i, b} => 3, + │ ^^^^^^^^^ + +warning: This assignment/binding to the left-hand-side variable `i` is unused. Consider removing this assignment/binding, or prefixing the left-hand-side variable with an underscore (e.g., `_i`), or renaming to `_` + ┌─ TEMPFILE1:45:13 + │ +45 │ Two{i, b} => 3, + │ ^^^^^^^^^ + + +task 2 lines 52-52: run 0x42::test_m::t1_check_scoping +return values: 3 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_scoping.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_scoping.move new file mode 100644 index 0000000000000..df3c1b8338584 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_enum_scoping.move @@ -0,0 +1,52 @@ +//# publish +module 0x42::m { + + public enum Inner has drop { + Inner1{ x: u64 } + Inner2{ x: u64, y: u64 } + } + + struct Box has drop { + x: u64 + } + + public enum Outer has drop { + None, + One{i: Inner}, + Two{i: Inner, b: Box}, + } + +} + +//# publish +module 0x42::test_m { + use 0x42::m::Inner; + use 0x42::m::Outer; + + /// Check for enum scoping bug; + /// result should be 3, not 4. + public fun check_scoping(i: &Inner): u64 { + let x = 3; + { + let x = 4; + { + match (i) { + Inner1{x: _} => true, + _ => false + }; + }; + }; + x + } + + fun t1_check_scoping(): u64 { + let o = Outer::One{i: Inner::Inner1{x: 43}}; + match (o) { + None => 0, + One{i} => check_scoping(&i), + Two{i, b} => 3, + } + } +} + +//# run 0x42::test_m::t1_check_scoping diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_field_access_closure.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_field_access_closure.exp new file mode 100644 index 0000000000000..9fe08835a3d47 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_field_access_closure.exp @@ -0,0 +1,9 @@ +processed 5 tasks +task 0 lines 1-15: publish [module 0xc0ffee::m {] +task 1 lines 17-39: publish [module 0xc0ffee::m2 {] +task 2 lines 41-41: run 0xc0ffee::m2::test1 +return values: 42 +task 3 lines 43-43: run 0xc0ffee::m2::test2 +return values: 87 +task 4 lines 45-45: run 0xc0ffee::m2::test3 +return values: 42 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_field_access_closure.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_field_access_closure.move new file mode 100644 index 0000000000000..adfd0e4fd5679 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_field_access_closure.move @@ -0,0 +1,45 @@ +//# publish +module 0xc0ffee::m { + public struct Func1 { + bar: ||u64 + } has copy, drop; + + + public enum Func2 { + V1 { bar: |u64|u64 }, + V2 { bar: |u64|u64, x: u64 }, + } has copy, drop; + + public struct Func3(||u64) has copy, drop; + +} + +//# publish +module 0xc0ffee::m2 { + use 0xc0ffee::m::Func1; + use 0xc0ffee::m::Func2; + use 0xc0ffee::m::Func3; + + fun test1(): u64 { + let f = Func1{ bar: || 42}; + (f.bar)() + } + + + fun test2(): u64 { + let f1 = Func2::V1{ bar: |x| x}; + let f2 = Func2::V2{ bar: |x| x + 1, x: 44}; + (f1.bar)(42) + (f2.bar)(f2.x) + } + + fun test3(): u64 { + let f = Func3(|| 42); + (f.0)() + } +} + +//# run 0xc0ffee::m2::test1 + +//# run 0xc0ffee::m2::test2 + +//# run 0xc0ffee::m2::test3 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_freeze_mut_ref.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_freeze_mut_ref.exp new file mode 100644 index 0000000000000..c8159c00f5e63 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_freeze_mut_ref.exp @@ -0,0 +1,9 @@ +processed 8 tasks +task 0 lines 1-6: publish [module 0x42::freeze_mut_ref {] +task 1 lines 8-100: publish [module 0x42::test_freeze_mut_ref {] +task 2 lines 102-102: run 0x42::test_freeze_mut_ref::test_1 +task 3 lines 104-104: run 0x42::test_freeze_mut_ref::test_2 +task 4 lines 106-106: run 0x42::test_freeze_mut_ref::test_3 +task 5 lines 108-108: run 0x42::test_freeze_mut_ref::test_5 +task 6 lines 110-110: run 0x42::test_freeze_mut_ref::test_6 +task 7 lines 112-112: run 0x42::test_freeze_mut_ref::test_7 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_freeze_mut_ref.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_freeze_mut_ref.move new file mode 100644 index 0000000000000..014708d8710c6 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_freeze_mut_ref.move @@ -0,0 +1,112 @@ +//# publish +module 0x42::freeze_mut_ref { + + public struct G has drop { f: u64 } + +} + +//# publish +module 0x42::test_freeze_mut_ref { + use std::vector; + use 0x42::freeze_mut_ref::G; + + + public fun borrow_mut( + map: &mut vector, + ): &Element { + vector::borrow_mut(map, 0) + } + + public fun borrow_mut2( + v: &mut Element, + ): &Element { + v + } + + fun t1(s: &mut G): &G { + s + } + + fun t2(u1: &mut u64, u2: &mut u64): (&mut u64, &mut u64) { + (u1, u2) + } + + + public fun t5(s: &mut G): (u64, u64, u64) { + let x = 0; + let f = { x = x + 1; &mut ({x = x + 1; s}).f }; + let y = &mut 2; + let z: &u64; + + *({*f = 0; z = y; f}) = 2; + (*z, *f, x) + } + + + fun test_1() { + let x: &u64 = &mut 0; + assert!(*x == 0, 0); + let g = G {f: 3}; + let y = t1(&mut g); + assert!(y.f == 3, 1); + } + + fun test_2() { + let para_g = G { f: 50 }; + let (z, f, x) = t5(&mut para_g); + assert!(z == 2, 0); + assert!(f == 2, 1); + assert!(x == 2, 2); + } + + + fun test_3() { + let vec = vector[0u64]; + let y = borrow_mut(&mut vec); + assert!(*y == 0, 0); + } + + // TODO: this case is not handled + // fun test_4() { + // let x: &u64; + // let y: &u64; + // (x, y) = t2(&mut 3, &mut 4); + // assert!(*x == 3, 2); + // assert!(*y == 4, 3); + // } + + fun test_5() { + let x = 3; + let a = borrow_mut2(&mut x); + assert!(*a == 3, 0); + } + + + fun test_6() { + let s1 = G {f: 2}; + let s2 = G {f: 3}; + let x; + x = if (true) &s1 else &mut s2; + assert!(x.f == 2, 0); + } + + fun test_7() { + let s1 = G {f: 2}; + let s2 = G {f: 3}; + let x: &G = if (true) &s1 else &mut s2; + assert!(x.f == 2, 0); + } + +} + +//# run 0x42::test_freeze_mut_ref::test_1 + +//# run 0x42::test_freeze_mut_ref::test_2 + +//# run 0x42::test_freeze_mut_ref::test_3 + +//# run 0x42::test_freeze_mut_ref::test_5 + +//# run 0x42::test_freeze_mut_ref::test_6 + +//# run 0x42::test_freeze_mut_ref::test_7 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_func_ref_param.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_func_ref_param.exp new file mode 100644 index 0000000000000..417bd8c3b113c --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_func_ref_param.exp @@ -0,0 +1,4 @@ +processed 3 tasks +task 0 lines 1-4: publish [module 0x77::m {] +task 1 lines 6-14: publish [module 0x77::m_func_ref_param {] +task 2 lines 16-16: run 0x77::m_func_ref_param::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_func_ref_param.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_func_ref_param.move new file mode 100644 index 0000000000000..f0cd982e31d4d --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_func_ref_param.move @@ -0,0 +1,16 @@ +//# publish +module 0x77::m { + public struct Func(|&u64|bool) has drop; +} + +//# publish +module 0x77::m_func_ref_param { + use 0x77::m::Func; + + fun test() { + let f: Func = |x| *x > 0; + assert!(f(&1)) + } +} + +//# run 0x77::m_func_ref_param::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_fv_enum.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_fv_enum.exp new file mode 100644 index 0000000000000..d0e75c92a3ff0 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_fv_enum.exp @@ -0,0 +1,6 @@ +processed 5 tasks +task 0 lines 1-22: publish [module 0x66::fv_enum_basic {] +task 1 lines 24-82: publish [module 0x66::fv_enum_basic_public {] +task 2 lines 84-84: run 0x66::fv_enum_basic_public::call_square --args 7 +task 3 lines 86-86: run 0x66::fv_enum_basic_public::test_enum_in_another_enum +task 4 lines 88-88: run 0x66::fv_enum_basic_public::test_fun_vec diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_fv_enum.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_fv_enum.move new file mode 100644 index 0000000000000..fe551e092389d --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_fv_enum.move @@ -0,0 +1,88 @@ +//# publish +module 0x66::fv_enum_basic { + public enum Action has drop { + Noop, + Call(|u64|u64), + } + + public enum Mapper has drop { + Id(|T|R has copy + drop + store), + Twice(Version), + } + + public enum Version has copy,store, drop { + V1 { v1: |T|R has copy + drop + store }, + } + + public enum FunVec has drop { + V1 { v1: vector<|&mut T|T has copy + drop + store> }, + V2 { v0: u64, v1: vector<|&mut T|T has copy + drop + store> }, + } + +} + +//# publish +module 0x66::fv_enum_basic_public { + use 0x66::fv_enum_basic::Action; + use 0x66::fv_enum_basic::Mapper; + use 0x66::fv_enum_basic::Version; + use 0x66::fv_enum_basic::FunVec; + + fun square(x: u64): u64 { x * x } + + fun call_square(x: u64) { + let act = Action::Call(square); + let v = match (act) { + Action::Call(f) => f(x), + _ => 0 + }; + assert!(v == 49); + } + + #[persistent] + fun add_k_persistent(x: u64, k: u64): u64 { x + k } + + fun test_enum_in_another_enum() { + let k = 3; + let add_k: |u64|u64 has copy + drop + store = |x: u64| add_k_persistent(x, k); + let v1 = Version::V1 { v1: add_k }; + let v2 = Mapper::Twice(v1); + let v = match (&mut v2) { + Mapper::Twice(v1) => (v1.v1)((v1.v1)(10)), + Mapper::Id(f) => (*f)(10), + }; + assert!(v == 16, 99); + } + + #[persistent] + fun add_k_persistent_ref(x: &mut u64, k: u64): u64 { *x = *x + 1; *x + k } + + fun test_fun_vec() { + use std::vector; + let k = 3; + let add_k: |&mut u64|u64 has copy + store + drop = |x: &mut u64| add_k_persistent_ref(x, k); + let v1 = FunVec::V1 { v1: vector[add_k, add_k] }; + match (v1) { + FunVec::V1 { v1 } => { + let add = vector::pop_back(&mut v1); + let v = 3; + let x = add(&mut v); + assert!(v == 4, 0); + assert!(x == 7, 1); + vector::push_back(&mut v1, add); + let _m = FunVec::V2 { v0: 10, v1 }; + } + FunVec::V2 { v0: _, v1 } => { + vector::destroy_empty(v1); + assert!(false, 2); + } + }; + } + +} + +//# run 0x66::fv_enum_basic_public::call_square --args 7 + +//# run 0x66::fv_enum_basic_public::test_enum_in_another_enum + +//# run 0x66::fv_enum_basic_public::test_fun_vec diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_match_cover.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_match_cover.exp new file mode 100644 index 0000000000000..34dee83014da5 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_match_cover.exp @@ -0,0 +1,29 @@ +processed 8 tasks +task 0 lines 1-17: publish [module 0xc0ffee::m {] +task 1 lines 19-70: publish [module 0xc0ffee::test_m {] +task 2 lines 72-93: publish [module 0xc0ffee::n {] +task 3 lines 95-110: publish [module 0xc0ffee::test_n {] +task 4 lines 112-134: publish [module 0xc0ffee::o {] +task 5 lines 136-169: publish [module 0xc0ffee::test_o {] +task 6 lines 171-193: publish [module 0xc0ffee::o_fail {] +task 7 lines 195-230: publish [module 0xc0ffee::test_o_fail {] +Error: compilation errors: + error: unreachable pattern + ┌─ TEMPFILE7:204:13 + │ +204 │ E::V1 {..} => {} + │ ^^^^^^^^^^ + +error: unreachable pattern + ┌─ TEMPFILE7:214:13 + │ +214 │ E::V1 {b: G::G2{ a: H::H2 {b: _}}, a: F::F1} => {}, + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + ┌─ TEMPFILE7:223:13 + │ +223 │ E::V1 {..} => {} + │ ^^^^^^^^^^ + + diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_match_cover.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_match_cover.move new file mode 100644 index 0000000000000..9e1041aa3c278 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_match_cover.move @@ -0,0 +1,230 @@ +//# publish +module 0xc0ffee::m { + public enum A has drop { + V1 { a: Q, b: R}, + } + + public enum Q has drop { + Q1, + Q2, + } + + public enum R has drop { + R1, + R2, + } + +} + +//# publish +module 0xc0ffee::test_m { + use 0xc0ffee::m::A; + use 0xc0ffee::m::Q; + use 0xc0ffee::m::R; + + public fun test1(a: A) { + match (a) { + A::V1 { a: Q::Q1, b: _ } => {}, + A::V1 { a: _, b: R::R1 } => {}, + A::V1 {a: Q::Q2, b: R::R2} => {}, + } + } + + public fun test2(a: A) { + match (a) { + A::V1 { a: Q::Q1, b: _ } => {}, + A::V1 { a: _, b: R::R1 } => {}, + A::V1 {..} => {}, + } + } + + public fun test3(a: A) { + match (a) { + A::V1 { a: Q::Q1, b: _ } => {}, + A::V1 { a: _, b: R::R1 } => {}, + _ => {}, + } + } + + public fun test4(a: A) { + match (a) { + A::V1 { a: Q::Q1, b: _ } => {}, + A::V1 {..} => {}, + } + } + + public fun test5(a: A) { + match (a) { + A::V1 { a: Q::Q1, b: _ } => {}, + A::V1 { a: Q::Q2, b: _ } => {}, + } + } + + public fun test6(a: A) { + match (a) { + A::V1 { a: Q::Q1, b: _ } => {}, + A::V1 { a: Q::Q2, b: _ } if true => {}, + _ => {}, + } + } +} + +//# publish +module 0xc0ffee::n { + public enum A has drop { + V1 { a: P, b: Q, c: R}, + } + + public enum P has drop { + P1, + P2, + } + + public enum Q has drop { + Q1, + Q2, + } + + public enum R has drop { + R1, + R2, + } + +} + +//# publish +module 0xc0ffee::test_n { + use 0xc0ffee::n::A; + use 0xc0ffee::n::P; + use 0xc0ffee::n::Q; + use 0xc0ffee::n::R; + + public fun test(a: A) { + match (a) { + A::V1 { a: P::P1, b: _, c: _ } => {}, + A::V1 { a: _, b: Q::Q1, c: _ } => {}, + A::V1 { a: _, b: _, c: R::R1 } => {}, + A::V1 { a: P::P2, b: Q::Q2, c: R::R2 } => {}, + } + } +} + +//# publish +module 0xc0ffee::o { + public enum E has drop { + V1 { a: F, b: G }, + V2 { a: F, b: G, c: H } + } + + public enum F has drop { + F1, + F2 { a: G } + } + + public enum G has drop { + G1 { a: H, b: H }, + G2 { a: H } + } + + public enum H has drop { + H1 { a: u64}, + H2 { b: u64 } + } + +} + +//# publish +module 0xc0ffee::test_o { + use 0xc0ffee::o::E; + use 0xc0ffee::o::F; + use 0xc0ffee::o::G; + use 0xc0ffee::o::H; + + public fun test1(e: E) { + match (e) { + E::V1 {b: _, ..} => {}, + E::V2 {..} => {} + } + } + + public fun test2(e: E) { + match (e) { + E::V1 {b: G::G1{ a: H::H1 { a: _}, b: _}, ..} => {}, + E::V1 {b: G::G1{ a: _, b: H::H1 { .. }}, ..} => {}, + E::V1 {b: _, a: F::F1} => {}, + E::V1 {b: _, a: F::F2 {..} } => {}, + E::V2 {..} => {} + } + } + + public fun test3(e: E) { + match (e) { + E::V1 {b: G::G1{ .. }, a: _} => {}, + E::V1 {b: _, a: F::F2 {..} } => {}, + E::V1 {b: G::G2{ a: H::H2 {b: _}}, a: F::F1} => {}, + E::V1 {b: _, a: F::F1} => {}, + E::V2 {..} => {} + } + } +} + +//# publish +module 0xc0ffee::o_fail { + public enum E has drop { + V1 { a: F, b: G }, + V2 { a: F, b: G, c: H } + } + + public enum F has drop { + F1, + F2 { a: G } + } + + public enum G has drop { + G1 { a: H, b: H }, + G2 { a: H } + } + + public enum H has drop { + H1 { a: u64}, + H2 { b: u64 } + } + +} + +//# publish +module 0xc0ffee::test_o_fail { + use 0xc0ffee::o_fail::E; + use 0xc0ffee::o_fail::F; + use 0xc0ffee::o_fail::G; + use 0xc0ffee::o_fail::H; + + public fun test1(e: E) { + match (e) { + E::V1 {b: _, ..} => {}, + E::V1 {..} => {} + E::V2 {..} => {} + } + } + + public fun test2(e: E) { + match (e) { + E::V2 {..} => {} + E::V1 {b: G::G1{ .. }, a: _} => {}, + E::V1 {b: _, a: F::F2 {..} } => {}, + E::V1 {b: _, a: F::F1} => {}, + E::V1 {b: G::G2{ a: H::H2 {b: _}}, a: F::F1} => {}, + } + } + + public fun test3(e: E) { + match (e) { + E::V1 {b: G::G1{ .. }, a: F::F1} => {}, + E::V1 {b: G::G2{ .. }, a: F::F2 {..}} => {}, + E::V1 {a: F::F2 {..}, ..} => {}, + E::V1 {b: _, a: F::F1} => {}, + E::V1 {..} => {} + E::V2 {..} => {} + } + } +} diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_match_critical_edge.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_match_critical_edge.exp new file mode 100644 index 0000000000000..b0c9120be3f08 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_match_critical_edge.exp @@ -0,0 +1,17 @@ +processed 9 tasks +task 0 lines 6-18: publish [module 0x815::m {] +task 1 lines 20-79: publish [module 0x815::m_bug_14733_match_critical_edge {] +task 2 lines 81-81: run 0x815::m_bug_14733_match_critical_edge::test1 +return values: 22 +task 3 lines 83-83: run 0x815::m_bug_14733_match_critical_edge::test2 +return values: 0 +task 4 lines 85-85: run 0x815::m_bug_14733_match_critical_edge::test3 +return values: 10 +task 5 lines 87-87: run 0x815::m_bug_14733_match_critical_edge::test4 +return values: 21 +task 6 lines 89-89: run 0x815::m_bug_14733_match_critical_edge::test5 +return values: 43 +task 7 lines 91-91: run 0x815::m_bug_14733_match_critical_edge::test6 +return values: 25 +task 8 lines 93-93: run 0x815::m_bug_14733_match_critical_edge::test7 +return values: 15 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_match_critical_edge.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_match_critical_edge.move new file mode 100644 index 0000000000000..0bb46051c769b --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_match_critical_edge.move @@ -0,0 +1,93 @@ +// This source tests various scenarios of matches which introduce critical edges, which +// are eliminated by the split-critical-edge-processor. This kind of matches +// are also the only kind of code which can introduce those edges, so we are also +// testing functionality of the processor here. + +//# publish +module 0x815::m { + public enum Entity has drop { + Person { id: u64 }, + Institution { id: u64, admin: Admin } + } + + public enum Admin has drop { + Superuser, + User(u64) + } + +} + +//# publish +module 0x815::m_bug_14733_match_critical_edge { + use 0x815::m::Entity; + use 0x815::m::Admin; + + + // Ensure function is inlined so we create nested matches in the next one. + inline fun id(s: &Entity): u64 { + match (s) { + Person{id} if *id > 10 => *id, + Institution{id, ..} => *id, + _ => 0 + } + } + + fun admin_id(e: &Entity): u64 { + match (e) { + Institution{admin: Admin::Superuser, ..} => 1 + id(e), + Institution{admin: Admin::User(id), ..} if *id > 10 => *id + id(e), + Institution{admin: Admin::User(id), ..} if *id <= 10 => id(e) + 5, + _ => id(e) + + } + } + + fun test1(): u64 { + let e = Entity::Person{id: 22}; + id(&e) + } + + fun test2(): u64 { + let e = Entity::Person{id: 10}; + id(&e) + } + + fun test3(): u64 { + let e = Entity::Institution { id: 10, admin: Admin::Superuser }; + id(&e) + } + + fun test4(): u64 { + let e = Entity::Institution{id: 20, admin: Admin::Superuser}; + admin_id(&e) + } + + fun test5(): u64 { + let e = Entity::Institution{id: 20, admin: Admin::User(23)}; + admin_id(&e) + } + + fun test6(): u64 { + let e = Entity::Institution{id: 20, admin: Admin::User(8)}; + admin_id(&e) + } + + fun test7(): u64 { + let e = Entity::Person{id: 15}; + admin_id(&e) + } +} + +//# run 0x815::m_bug_14733_match_critical_edge::test1 + +//# run 0x815::m_bug_14733_match_critical_edge::test2 + +//# run 0x815::m_bug_14733_match_critical_edge::test3 + +//# run 0x815::m_bug_14733_match_critical_edge::test4 + +//# run 0x815::m_bug_14733_match_critical_edge::test5 + +//# run 0x815::m_bug_14733_match_critical_edge::test6 + +//# run 0x815::m_bug_14733_match_critical_edge::test7 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mut_ref_downgrade.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mut_ref_downgrade.exp new file mode 100644 index 0000000000000..88cf67c815773 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mut_ref_downgrade.exp @@ -0,0 +1,19 @@ +processed 3 tasks +task 0 lines 1-4: publish [module 0xc0ffee::m {] +task 1 lines 6-30: publish [module 0xc0ffee::m_mut_ref_downgrade {] +Error: compilation errors: + error: cannot pass `&mut ||u64 has copy + drop` to a function which expects argument of type `&mut ||u64 has drop` + ┌─ TEMPFILE1:19:30 + │ +19 │ assn<||u64 has drop>(&mut b, a); + │ ^^^^^^ + + +task 2 lines 32-32: run 0xc0ffee::m_mut_ref_downgrade::foo +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mut_ref_downgrade.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mut_ref_downgrade.move new file mode 100644 index 0000000000000..57a6ae000d878 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mut_ref_downgrade.move @@ -0,0 +1,32 @@ +//# publish +module 0xc0ffee::m { + public struct NoCopy has drop; +} + +//# publish +module 0xc0ffee::m_mut_ref_downgrade { + + public fun assn(ref: &mut T, x: T){ + *ref = x; + } + + public fun foo() { + use 0xc0ffee::m; + + let x = m::NoCopy; + + let a: ||u64 has drop = ||{ + let m::NoCopy = x; + 1 + }; + + let b: ||u64 has drop + copy = ||1; + + assn<||u64 has drop>(&mut b, a); + + b(); + b(); + } +} + +//# run 0xc0ffee::m_mut_ref_downgrade::foo diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mut_refs_2.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mut_refs_2.exp new file mode 100644 index 0000000000000..8256cf8f02bda --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mut_refs_2.exp @@ -0,0 +1,4 @@ +processed 3 tasks +task 0 lines 1-9: publish [module 0xc0ffee::m {] +task 1 lines 11-25: publish [module 0xc0ffee::test_m {] +task 2 lines 27-27: run 0xc0ffee::test_m::main diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mut_refs_2.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mut_refs_2.move new file mode 100644 index 0000000000000..aeccf3b04509c --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mut_refs_2.move @@ -0,0 +1,27 @@ +//# publish +module 0xc0ffee::m { + + public struct S has copy, drop { + a: u64, + b: u64, + } + +} + +//# publish +module 0xc0ffee::test_m { + use 0xc0ffee::m::S; + fun test(s: S): u64 { + let p = s; + let q = p; + let ref = &mut p.a; + *ref = 0; + q.a + } + + public fun main() { + assert!(test(S{a: 1, b: 2}) == 1, 5); + } +} + +//# run 0xc0ffee::test_m::main diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mutate_if.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mutate_if.exp new file mode 100644 index 0000000000000..ca969e662d448 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mutate_if.exp @@ -0,0 +1,4 @@ +processed 3 tasks +task 0 lines 1-9: publish [module 0xc0ffee::m {] +task 1 lines 11-35: publish [module 0xc0ffee::test_m {] +task 2 lines 37-37: run 0xc0ffee::test_m::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mutate_if.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mutate_if.move new file mode 100644 index 0000000000000..d66bf600f0ce5 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mutate_if.move @@ -0,0 +1,37 @@ +//# publish +module 0xc0ffee::m { + public struct S has copy, drop { + x: bool, + y: u64, + z: u64, + } + +} + +//# publish +module 0xc0ffee::test_m { + use 0xc0ffee::m::S; + + fun foo1(s: S): S { + let r = &mut (if (s.x) { s.y } else { s.z }); + *r = 2; + s + } + + fun foo2(s: S): S { + *&mut (if (s.x) s.y else s.z) = 2; + s + } + + fun test() { + let s1 = S { x: true, y: 1, z: 3 }; + let result1 = foo1(s1); + assert!(s1 == result1, 0); + + let s2 = S { x: false, y: 4, z: 5 }; + let result2 = foo2(s2); + assert!(s2 == result2, 1); + } +} + +//# run 0xc0ffee::test_m::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mutate_vector.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mutate_vector.exp new file mode 100644 index 0000000000000..443acd73566b7 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mutate_vector.exp @@ -0,0 +1,3 @@ +processed 2 tasks +task 0 lines 1-8: publish [module 0x42::m {] +task 1 lines 10-30: publish [module 0x42::test_m {] diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mutate_vector.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mutate_vector.move new file mode 100644 index 0000000000000..085e19549ab49 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_mutate_vector.move @@ -0,0 +1,30 @@ +//# publish +module 0x42::m { + + public struct Scalar has copy, store, drop { + data: vector + } + +} + +//# publish +module 0x42::test_m { + use std::vector; + use 0x42::m::Scalar; + + /// Creates a Scalar from an u8. + public fun new_scalar_from_u8(byte: u8): Scalar { + let s = scalar_zero(); + let byte_zero = vector::borrow_mut(&mut s.data, 0); + *byte_zero = byte; + s + } + + /// Returns 0 as a Scalar. + public fun scalar_zero(): Scalar { + Scalar { + data: x"00" + } + } + +} diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_nested.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_nested.exp new file mode 100644 index 0000000000000..e0acd24f85051 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_nested.exp @@ -0,0 +1,11 @@ +processed 6 tasks +task 0 lines 1-17: publish [module 0x42::test {] +task 1 lines 19-58: publish [module 0x42::test_nested {] +task 2 lines 60-60: run --verbose -- 0x42::test_nested::test1 +return values: 42 +task 3 lines 62-62: run --verbose -- 0x42::test_nested::test2 +return values: 42 +task 4 lines 64-64: run --verbose -- 0x42::test_nested::test3 +return values: 43 +task 5 lines 66-66: run --verbose -- 0x42::test_nested::test4 +return values: 43 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_nested.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_nested.move new file mode 100644 index 0000000000000..8fd292e839aa3 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_nested.move @@ -0,0 +1,66 @@ +//# publish +module 0x42::test { + public struct S0(A, B) has drop; + + public struct S1 has drop { + x: A, + y: B + } + + public enum E has drop { + V1(u8, S1), + V2 { + x: u8, + y: S0 + } + } +} + +//# publish +module 0x42::test_nested { + use 0x42::test::E; + use 0x42::test::S0; + use 0x42::test::S1; + + fun extract_first_u8(x: &E): u8 { + match (x) { + E::V1(a, ..) => *a, + E::V2 { x, .. } => *x, + } + } + + fun extract_last_u8(x: &E): u8 { + match (x) { + E::V1(.., S1 { x, ..}) => *x, + E::V2 { y: S0(x, ..), .. } => *x, + } + } + + fun test1(): u8 { + let x = E::V1(42, S1 { x: 43, y: true }); + extract_first_u8(&x) + } + + fun test2(): u8 { + let x = E::V2 { x: 42, y: S0(43, true) }; + extract_first_u8(&x) + } + + fun test3(): u8 { + let x = E::V1(42, S1 { x: 43, y: true }); + extract_last_u8(&x) + } + + fun test4(): u8 { + let x = E::V2 { x: 42, y: S0(43, true) }; + extract_last_u8(&x) + } +} + +//# run --verbose -- 0x42::test_nested::test1 + +//# run --verbose -- 0x42::test_nested::test2 + +//# run --verbose -- 0x42::test_nested::test3 + +//# run --verbose -- 0x42::test_nested::test4 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_nested_mutate.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_nested_mutate.exp new file mode 100644 index 0000000000000..b0ace6e838473 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_nested_mutate.exp @@ -0,0 +1,4 @@ +processed 3 tasks +task 0 lines 1-10: publish [module 0xc0ffee::m {] +task 1 lines 12-28: publish [module 0xc0ffee::test_m {] +task 2 lines 30-30: run 0xc0ffee::test_m::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_nested_mutate.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_nested_mutate.move new file mode 100644 index 0000000000000..a8f17e80cf0f6 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_nested_mutate.move @@ -0,0 +1,30 @@ +//# publish +module 0xc0ffee::m { + public struct S has copy, drop { + x: T, + } + + public struct T has copy, drop { + y: u64, + } +} + +//# publish +module 0xc0ffee::test_m { + use 0xc0ffee::m::S; + use 0xc0ffee::m::T; + + fun foo(s: S, p: S): S { + *&mut {s.x.y = p.x.y; s.x.y} = 1; + s + } + + public fun test() { + let s = S { x: T { y: 42 } }; + let p = S { x: T { y: 43 } }; + let result = foo(s, p); + assert!(result.x.y == 43, 0); + } +} + +//# run 0xc0ffee::test_m::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_pack_unpack_ref.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_pack_unpack_ref.exp new file mode 100644 index 0000000000000..1204994dd40b2 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_pack_unpack_ref.exp @@ -0,0 +1,22 @@ +processed 3 tasks +task 0 lines 1-13: publish [module 0x42::pack_unpack_ref {] +task 1 lines 15-38: publish [module 0x42::test_pack_unpack_ref {] +Error: compilation errors: + bug: bytecode verification failed with unexpected status code `CALL_BORROWED_MUTABLE_REFERENCE_ERROR`: +Error message: none + ┌─ TEMPFILE1:22:13 + │ +22 │ let G{ x1, x2, s } = &mut g; + │ ^^^^^^^^^^^^^^^ + │ + = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) + + +task 2 lines 40-40: run 0x42::test_pack_unpack_ref::unpack_ref_G +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_pack_unpack_ref.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_pack_unpack_ref.move new file mode 100644 index 0000000000000..3515138f0b8c7 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_pack_unpack_ref.move @@ -0,0 +1,40 @@ +//# publish +module 0x42::pack_unpack_ref { + public struct S has drop { + f: u64, + g: u64 + } + + public struct G has drop { + x1: u64, + x2: u64, + s: S, + } +} + +//# publish +module 0x42::test_pack_unpack_ref { + use 0x42::pack_unpack_ref::S; + use 0x42::pack_unpack_ref::G; + + fun unpack_ref_G() { + let s = S {f: 0, g: 1}; + let g = G {x1: 2, x2: 3, s}; + let G{ x1, x2, s } = &mut g; + let S {f, g} = s; + assert!(*f == 0, 0); + assert!(*g == 1, 1); + assert!(*x1 == 2, 2); + assert!(*x2 == 3, 3); + *x1 = *x1 + 1; + *x2 = *x2 + 1; + *f = *f + 1; + *g = *g + 1; + assert!(*f == 1, 0); + assert!(*g == 2, 1); + assert!(*x1 == 3, 2); + assert!(*x2 == 4, 3); + } +} + +//# run 0x42::test_pack_unpack_ref::unpack_ref_G diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_phantoms.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_phantoms.exp new file mode 100644 index 0000000000000..3e70443afee80 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_phantoms.exp @@ -0,0 +1,4 @@ +processed 3 tasks +task 0 lines 1-13: publish [module 0x42::phantoms {] +task 1 lines 15-24: publish [module 0x42::phantoms2 {] +task 2 lines 27-27: run 0x42::phantoms2::test_phantoms diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_phantoms.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_phantoms.move new file mode 100644 index 0000000000000..432170a6fe70f --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_phantoms.move @@ -0,0 +1,27 @@ +//# publish +module 0x42::phantoms { + + + /// A struct with a phantom parameter. Even if the parameter is not dropable, the struct should still be. + public struct S has drop { + addr: address, + } + + struct T {} // no abilities + + +} + +//# publish +module 0x42::phantoms2 { + use 0x42::phantoms::S; + use 0x42::phantoms::T; + + fun test_phantoms() { + let _s = S{ addr: @0x12 }; + // _s is dropped + } +} + + +//# run 0x42::phantoms2::test_phantoms diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_positional_fields.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_positional_fields.exp new file mode 100644 index 0000000000000..b332939913841 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_positional_fields.exp @@ -0,0 +1,4 @@ +processed 3 tasks +task 0 lines 1-4: publish [module 0x42::test {] +task 1 lines 6-18: publish [module 0x42::test_positional_fields {] +task 2 lines 20-20: run --verbose -- 0x42::test_positional_fields::test_ok diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_positional_fields.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_positional_fields.move new file mode 100644 index 0000000000000..ebcab6e7ba4f1 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_positional_fields.move @@ -0,0 +1,20 @@ +//# publish +module 0x42::test { + public struct Tup(T, U); +} + +//# publish +module 0x42::test_positional_fields { + use 0x42::test::Tup; + + fun baz(x: u64, y: u64): u64 { + let Tup(y, x) = Tup(x, y); + y - x + } + + fun test_ok() { + assert!(baz(2, 1) == 1, 42); + } +} + +//# run --verbose -- 0x42::test_positional_fields::test_ok diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_projection.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_projection.exp new file mode 100644 index 0000000000000..9aa677b04e789 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_projection.exp @@ -0,0 +1,15 @@ +processed 8 tasks +task 0 lines 1-9: publish [module 0x42::test {] +task 1 lines 11-76: publish [module 0x42::test_projection {] +task 2 lines 78-78: run --verbose -- 0x42::test_projection::test_proj_0 +return values: 42 +task 3 lines 80-80: run --verbose -- 0x42::test_projection::test_proj_0_ref +return values: 42 +task 4 lines 82-82: run --verbose -- 0x42::test_projection::test_proj_2 +return values: true +task 5 lines 84-84: run --verbose -- 0x42::test_projection::test_proj_2_ref +return values: true +task 6 lines 86-86: run --verbose -- 0x42::test_projection::test_get_x +return values: 42 +task 7 lines 88-88: run --verbose -- 0x42::test_projection::test_get_x_ref +return values: 42 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_projection.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_projection.move new file mode 100644 index 0000000000000..62699cffe9a76 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_projection.move @@ -0,0 +1,88 @@ +//# publish +module 0x42::test { + public struct S(A, B, C) has drop; + + public struct T has drop { + x: A, + y: B + } +} + +//# publish +module 0x42::test_projection { + use 0x42::test::S; + use 0x42::test::T; + + + fun proj_0(s: S): A { + let S(x, ..) = s; + x + } + + fun proj_0_ref(x: &S): &A { + let S(x, ..) = x; + x + } + + fun proj_2(x: S): C { + let S(.., z) = x; + z + } + + fun proj_2_ref(x: &S): &C { + let S(.., z) = x; + z + } + + fun get_x(s: T): A { + let T { x, .. } = s; + x + } + + fun get_x_ref(s: &T): &A { + let T { x, .. } = s; + x + } + + fun test_proj_0(): u8 { + let x = S(42, @0x1, true); + proj_0(x) + } + + fun test_proj_0_ref(): u8 { + let x = S(42, @0x1, true); + *proj_0_ref(&x) + } + + fun test_proj_2(): bool { + let x = S(42, @0x1, true); + proj_2(x) + } + + fun test_proj_2_ref(): bool { + let x = S(42, @0x1, true); + *proj_2_ref(&x) + } + + fun test_get_x(): u8 { + let x = T{ x: 42, y: true }; + get_x(x) + } + + fun test_get_x_ref(): u8 { + let x = T{ x: 42, y: true }; + *get_x_ref(&x) + } +} + +//# run --verbose -- 0x42::test_projection::test_proj_0 + +//# run --verbose -- 0x42::test_projection::test_proj_0_ref + +//# run --verbose -- 0x42::test_projection::test_proj_2 + +//# run --verbose -- 0x42::test_projection::test_proj_2_ref + +//# run --verbose -- 0x42::test_projection::test_get_x + +//# run --verbose -- 0x42::test_projection::test_get_x_ref diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_sequential_assign_struct.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_sequential_assign_struct.exp new file mode 100644 index 0000000000000..a6f27f1dc0423 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_sequential_assign_struct.exp @@ -0,0 +1,4 @@ +processed 3 tasks +task 0 lines 1-11: publish [module 0xc0ffee::m {] +task 1 lines 13-33: publish [module 0xc0ffee::test_m {] +task 2 lines 35-35: run 0xc0ffee::test_m::main diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_sequential_assign_struct.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_sequential_assign_struct.move new file mode 100644 index 0000000000000..d4768e27c966a --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_sequential_assign_struct.move @@ -0,0 +1,35 @@ +//# publish +module 0xc0ffee::m { + public struct Foo has copy, drop { + a: u64, + b: u64, + c: u64, + d: u64, + e: u64, + } + +} + +//# publish +module 0xc0ffee::test_m { + use 0xc0ffee::m::Foo; + fun sequential(p: Foo): Foo { + let a = p; + let b = a; + let c = b; + let d = c; + let e = d; + e + } + + public fun main() { + assert!( + sequential( + Foo {a: 1, b: 2, c: 3, d: 4, e: 5} + ) == Foo {a: 1, b: 2, c: 3, d: 4, e: 5}, + 0 + ); + } +} + +//# run 0xc0ffee::test_m::main diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_struct_assign_swap.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_struct_assign_swap.exp new file mode 100644 index 0000000000000..dc9df9df0729c --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_struct_assign_swap.exp @@ -0,0 +1,11 @@ +processed 6 tasks +task 0 lines 1-7: publish [module 0xc0ffee::m {] +task 1 lines 9-45: publish [module 0xc0ffee::test_m {] +task 2 lines 47-47: run 0xc0ffee::test_m::test1 +return values: 2, 1 +task 3 lines 49-49: run 0xc0ffee::test_m::swap2 +return values: 55, 44 +task 4 lines 51-51: run 0xc0ffee::test_m::test3 +return values: 2, 1 +task 5 lines 53-53: run 0xc0ffee::test_m::test4 +return values: 2, 1 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_struct_assign_swap.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_struct_assign_swap.move new file mode 100644 index 0000000000000..c5fc56a288aa9 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_struct_assign_swap.move @@ -0,0 +1,53 @@ +//# publish +module 0xc0ffee::m { + public struct S { + f: u32, + g: u32, + } +} + +//# publish +module 0xc0ffee::test_m { + use 0xc0ffee::m::S; + fun swap1(x: u32, y: u32): (u32, u32) { + let S { f: x, g: y } = S { f: y, g: x }; + (x, y) + } + + fun swap2(): (u32, u32) { + let x = 44; + let y = 55; + let S { f: _x, g: _y } = S { f: y, g: x }; + (_x, _y) + } + + fun swap3(x: u32, y: u32): (u32, u32) { + let S { f: y, g: x } = S { f: x, g: y }; + (x, y) + } + + fun swap4(f: u32, g: u32): (u32, u32) { + let S { f: g, g: f } = S { f: f, g: g }; + (f, g) + } + + fun test1(): (u32, u32) { + swap1(1, 2) + } + + fun test3(): (u32, u32) { + swap3(1, 2) + } + + fun test4(): (u32, u32) { + swap4(1, 2) + } +} + +//# run 0xc0ffee::test_m::test1 + +//# run 0xc0ffee::test_m::swap2 + +//# run 0xc0ffee::test_m::test3 + +//# run 0xc0ffee::test_m::test4 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_tuple_swap.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_tuple_swap.exp new file mode 100644 index 0000000000000..a098bd6a3014a --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_tuple_swap.exp @@ -0,0 +1,7 @@ +processed 4 tasks +task 0 lines 1-8: publish [module 0xc0ffee::m {] +task 1 lines 10-30: publish [module 0xc0ffee::test_m {] +task 2 lines 32-32: run 0xc0ffee::test_m::test4 +return values: { 222 }, { 111 } +task 3 lines 34-34: run 0xc0ffee::test_m::swap5 +return values: 258, 147 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_tuple_swap.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_tuple_swap.move new file mode 100644 index 0000000000000..16c8bdc8c7586 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_tuple_swap.move @@ -0,0 +1,34 @@ +//# publish +module 0xc0ffee::m { + + public struct W { + inner: u64, + } + +} + +//# publish +module 0xc0ffee::test_m { + use 0xc0ffee::m::W; + + fun swap4(a: W, b: W): (W, W) { + (a, b) = (b, a); + (a, b) + } + + fun swap5(): (u64, u64) { + let x = 147; + let y = 258; + (W {inner: x}, W {inner: y}) = (W {inner: y}, W {inner: x}); + (x, y) + } + + public fun test4(): (W, W) { + swap4(W{inner: 111}, W{inner: 222}) + } + +} + +//# run 0xc0ffee::test_m::test4 + +//# run 0xc0ffee::test_m::swap5 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_update_variant_field.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_update_variant_field.exp new file mode 100644 index 0000000000000..f34b960aa40d8 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_update_variant_field.exp @@ -0,0 +1,9 @@ +processed 5 tasks +task 0 lines 1-10: publish [module 0x815::m {] +task 1 lines 12-45: publish [module 0x815::m_bug_14300_update_variant_field {] +task 2 lines 47-47: run 0x815::m_bug_14300_update_variant_field::update_common_field +return values: 15 +task 3 lines 49-49: run 0x815::m_bug_14300_update_variant_field::update_non_common_field +return values: 15 +task 4 lines 51-51: run 0x815::m_bug_14300_update_variant_field::update_common_field_different_offset +return values: 15 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_update_variant_field.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_update_variant_field.move new file mode 100644 index 0000000000000..48a2eb8496565 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_update_variant_field.move @@ -0,0 +1,51 @@ +//# publish +module 0x815::m { + + public enum CommonFields has drop { + Foo{x: u64, y: u8}, + Bar{x: u64, y: u8, z: u32} + Baz{y: u8} + } + +} + +//# publish +module 0x815::m_bug_14300_update_variant_field { + use 0x815::m::CommonFields; + + fun update_common_field(): u64 { + let common = CommonFields::Bar { + x: 30, + y: 40, + z: 50 + }; + common.x = 15; + common.x + } + + fun update_non_common_field(): u32 { + let common = CommonFields::Bar { + x: 30, + y: 40, + z: 50 + }; + common.z = 15; + common.z + } + + fun update_common_field_different_offset(): u8 { + let common = CommonFields::Bar { + x: 30, + y: 40, + z: 50 + }; + common.y = 15; + common.y + } +} + +//# run 0x815::m_bug_14300_update_variant_field::update_common_field + +//# run 0x815::m_bug_14300_update_variant_field::update_non_common_field + +//# run 0x815::m_bug_14300_update_variant_field::update_common_field_different_offset diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_valid.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_valid.exp new file mode 100644 index 0000000000000..5a9512fc81701 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_valid.exp @@ -0,0 +1,11 @@ +processed 10 tasks +task 0 lines 1-7: publish [module 0x42::test {] +task 1 lines 9-157: publish [module 0x42::test_valid {] +task 2 lines 159-159: run --verbose -- 0x42::test_valid::test1 +task 3 lines 161-161: run --verbose -- 0x42::test_valid::test2 +task 4 lines 163-163: run --verbose -- 0x42::test_valid::test3 +task 5 lines 165-165: run --verbose -- 0x42::test_valid::test4 +task 6 lines 167-167: run --verbose -- 0x42::test_valid::test5 +task 7 lines 169-169: run --verbose -- 0x42::test_valid::test6 +task 8 lines 171-171: run --verbose -- 0x42::test_valid::test7 +task 9 lines 173-173: run --verbose -- 0x42::test_valid::test8 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_valid.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_valid.move new file mode 100644 index 0000000000000..0d251879a6164 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/migrated_tests/public_valid.move @@ -0,0 +1,173 @@ +//# publish +module 0x42::test { + public struct Coin(u256) has drop; + + public struct Wrapper(T) has drop; + +} + +//# publish +module 0x42::test_valid { + use 0x42::test::Coin; + use 0x42::test::Wrapper; + + fun add1_old(x: u256): u256 { + x = x + 1; + x + } + + fun add1_new(x: u256): u256 { + x += 1; + x + } + + fun test1() { + assert!(add1_old(42) == add1_new(42)); + } + + fun inc_new(x: &mut u256) { + *x += 1; + } + + fun inc_old(x: &mut u256) { + *x = *x + 1; + } + + fun test2() { + let x = 42; + let y = x; + inc_new(&mut x); + inc_old(&mut y); + assert!(x == y); + } + + fun coin_inc_new_1(c: &mut Coin) { + c.0 += 1; + } + + fun coin_inc_new_2(c: &mut Coin) { + let p = &mut c.0; + *p = *p + 1; + } + + fun coin_inc_old_1(c: &mut Coin) { + c.0 = c.0 + 1; + } + + fun coin_inc_old_2(c: &mut Coin) { + let p = &mut c.0; + *p = *p + 1; + } + + fun test3() { + let x = Coin(42); + let y = Coin(42); + let z = Coin(42); + let w = Coin(42); + coin_inc_new_1(&mut x); + coin_inc_new_2(&mut y); + coin_inc_old_1(&mut z); + coin_inc_old_2(&mut w); + assert!(&x == &y); + assert!(&x == &z); + assert!(&x == &w); + } + + fun inc_wrapped_coin_new(x: &mut Wrapper) { + x.0.0 += 1; + } + + fun inc_wrapped_coin_old(x: &mut Wrapper) { + x.0.0 = x.0.0 + 1; + } + + fun test4() { + let x = Wrapper(Coin(42)); + let y = Wrapper(Coin(42)); + inc_wrapped_coin_new(&mut x); + inc_wrapped_coin_old(&mut y); + assert!(x == y); + } + + fun inc_vec_new(x: &mut vector, index: u64) { + x[index] += 1; + } + + fun inc_vec_old(x: &mut vector, index: u64) { + x[index] = x[index] + 1; + } + + fun test5() { + let x = vector[42]; + let y = vector[42]; + inc_vec_new(&mut x, 0); + inc_vec_old(&mut y, 0); + assert!(x == y); + } + + fun inc_vec_coin_new(x: vector, index: u64): vector { + x[index].0 += 1; + x + } + + fun inc_vec_coin_old(x: vector, index: u64): vector { + x[index].0 = x[index].0 + 1; + x + } + + fun test6() { + let x = vector[Coin(42)]; + let y = vector[Coin(42)]; + let x = inc_vec_coin_new(x, 0); + let y = inc_vec_coin_old(y, 0); + assert!(x == y); + } + + fun inc_vec_wrapped_coin_new(x: vector>, index: u64): vector> { + x[index].0.0 += 1; + x + } + + fun inc_vec_wrapped_coin_old(x: vector>, index: u64): vector> { + x[index].0.0 = x[index].0.0 + 1; + x + } + + fun test7() { + let x = vector>[Wrapper(Coin(42))]; + let y = vector>[Wrapper(Coin(42))]; + let x = inc_vec_wrapped_coin_new(x, 0); + let y = inc_vec_wrapped_coin_old(y, 0); + assert!(x == y); + } + + fun x_plusplus(x: &mut u64): u64 { + let res = *x; + *x += 1; + res + } + + fun test8() { + let x = 0; + let y = vector[0, 1]; + y[x_plusplus(&mut x)] += 1; + assert!(y == vector[1, 1]); + } + +} + +//# run --verbose -- 0x42::test_valid::test1 + +//# run --verbose -- 0x42::test_valid::test2 + +//# run --verbose -- 0x42::test_valid::test3 + +//# run --verbose -- 0x42::test_valid::test4 + +//# run --verbose -- 0x42::test_valid::test5 + +//# run --verbose -- 0x42::test_valid::test6 + +//# run --verbose -- 0x42::test_valid::test7 + +//# run --verbose -- 0x42::test_valid::test8 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_field_api.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_field_api.exp new file mode 100644 index 0000000000000..83fb048e39c80 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_field_api.exp @@ -0,0 +1,66 @@ +processed 9 tasks +task 0 lines 1-4: publish [module 0x42::m2 {] +task 1 lines 6-35: publish [module 0x42::m {] +task 2 lines 37-93: publish [module 0x42::m2 {] +Error: compilation errors: + warning: This assignment/binding to the left-hand-side variable `ref_x` is unused. Consider removing this assignment/binding, or prefixing the left-hand-side variable with an underscore (e.g., `_ref_x`), or renaming to `_` + ┌─ TEMPFILE2:76:17 + │ +76 │ let ref_x = &mut_ref_d.x; + │ ^^^^^^^^^^^^ + +error: cannot perform borrow operation for field `x` for struct `0x42::m::Data4` since it has or may be instantiated with different types in variants + ┌─ TEMPFILE2:81:17 + │ +81 │ let ref_x = &mut_ref_d.x; + │ ^^^^^^^^^^^^ + + +task 3 lines 95-95: run 0x42::m2::test_v1 +Error: Function execution failed with VMError: { + major_status: FUNCTION_RESOLUTION_FAILURE, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 4 lines 97-97: run 0x42::m2::test_v1_mut_borrow +Error: Function execution failed with VMError: { + major_status: FUNCTION_RESOLUTION_FAILURE, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 5 lines 99-99: run 0x42::m2::test_v2_mut_borrow +Error: Function execution failed with VMError: { + major_status: FUNCTION_RESOLUTION_FAILURE, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 6 lines 101-101: run 0x42::m2::test_data2_mut_borrow +Error: Function execution failed with VMError: { + major_status: FUNCTION_RESOLUTION_FAILURE, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 7 lines 103-103: run 0x42::m2::test_data3_mut_borrow +Error: Function execution failed with VMError: { + major_status: FUNCTION_RESOLUTION_FAILURE, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 8 lines 105-105: run 0x42::m2::test_data4_mut_borrow +Error: Function execution failed with VMError: { + major_status: FUNCTION_RESOLUTION_FAILURE, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_field_api.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_field_api.move new file mode 100644 index 0000000000000..8fd7656530c9c --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_field_api.move @@ -0,0 +1,105 @@ +//# publish +module 0x42::m2 { + +} + +//# publish +module 0x42::m { + + friend 0x42::m2; + + friend enum Data has drop { + V1{x: u64}, + V2{x: u64, y: bool} + V3 + } + + friend enum Data2 has drop { + V1{x: T1}, + V2{y: u64, x: T2} + V3 + } + + friend enum Data3 has drop { + V1{x: T1}, + V2{y: u64, x: T2} + V3{x: T1} + } + + friend enum Data4 has drop { + V1{x: T1}, + V2{x: T2, y: u64} + V3 + } + +} + +//# publish +module 0x42::m2 { + + use 0x42::m::Data; + use 0x42::m::Data2; + use 0x42::m::Data3; + use 0x42::m::Data4; + + fun test_v1() { + let d = Data::V1{x: 43}; + assert!(d.x == 43, 1); + let Data::V1{x} = &d; + assert!(*x == 43, 2); + let data_x = &mut d; + let ref_x = &data_x.x; + assert!(*ref_x == 43, 3); + } + + fun test_v1_mut_borrow() { + let d = Data::V1{x: 43}; + let r = &mut d.x; + *r = 44; + assert!(d.x == 44, 1); + let r2 = &mut d; + r2.x = 45; + assert!(d.x == 45, 3); + } + + fun test_v2_mut_borrow() { + let d = Data::V2{x: 43, y: true}; + let mut_ref_d = &mut d; + let ref_x = &mut_ref_d.x; + assert!(*ref_x == 43, 1); + let ref_y = &mut_ref_d.y; + assert!(*ref_y == true, 2); + } + + fun test_data2_mut_borrow() { + let d = Data2::V2{y: 43, x: 44}; + d.x = 45; + } + + fun test_data3_mut_borrow() { + let d = Data3::V3{x: 44}; + let mut_ref_d = &mut d; + let ref_x = &mut_ref_d.x; + } + + fun test_data4_mut_borrow() { + let d = Data4::V2{x: 44, y: 43}; + let mut_ref_d = &mut d; + let ref_x = &mut_ref_d.x; + assert!(*ref_x == 44, 1); + } + + +} + +//# run 0x42::m2::test_v1 + +//# run 0x42::m2::test_v1_mut_borrow + +//# run 0x42::m2::test_v2_mut_borrow + +//# run 0x42::m2::test_data2_mut_borrow + +//# run 0x42::m2::test_data3_mut_borrow + +//# run 0x42::m2::test_data4_mut_borrow diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_pack_unpack_abort.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_pack_unpack_abort.exp new file mode 100644 index 0000000000000..3f10a2bf1b73b --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_pack_unpack_abort.exp @@ -0,0 +1,11 @@ +processed 3 tasks +task 0 lines 1-11: publish [module 0x42::m1 {] +task 1 lines 13-25: publish [module 0x42::m2 {] +task 2 lines 27-27: run 0x42::m2::test_pack_unpack_abort +Error: Function execution failed with VMError: { + major_status: STRUCT_VARIANT_MISMATCH, + sub_status: None, + location: 0x42::m1, + indices: [], + offsets: [(FunctionDefinitionIndex(5), 1)], +} diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_pack_unpack_abort.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_pack_unpack_abort.move new file mode 100644 index 0000000000000..204581818049e --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_pack_unpack_abort.move @@ -0,0 +1,27 @@ +//# publish +module 0x42::m1 { + + + public enum Result has copy, drop { + Ok(T), + Err(E) + } + + +} + +//# publish +module 0x42::m2 { + + use 0x42::m1::Result; + + public fun test_pack_unpack_abort() { + let result = Result::Ok(42); + assert!(result == Result::Ok(42), 1); + let Result::Err(err) = result; + assert!(err == 42, 2); + } + +} + +//# run 0x42::m2::test_pack_unpack_abort diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_pack_unpack_api.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_pack_unpack_api.exp new file mode 100644 index 0000000000000..292da4b56c0fe --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_pack_unpack_api.exp @@ -0,0 +1,7 @@ +processed 6 tasks +task 0 lines 1-22: publish [module 0x42::m1 {] +task 1 lines 24-72: publish [module 0x42::m2 {] +task 2 lines 74-74: run 0x42::m2::test_pack_unpack_result_ok +task 3 lines 76-76: run 0x42::m2::test_pack_unpack_result_err +task 4 lines 78-78: run 0x42::m2::test_unpack_enum_e +task 5 lines 80-80: run 0x42::m2::test_unpack_inner diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_pack_unpack_api.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_pack_unpack_api.move new file mode 100644 index 0000000000000..0d0e2df2e6e4d --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_pack_unpack_api.move @@ -0,0 +1,80 @@ +//# publish +module 0x42::m1 { + + + public enum Result has copy, drop { + Ok(T), + Err(E) + } + + + public enum E has drop { + A {x: u64}, + B {x: u64} + } + + public enum Inner { + Inner1{ x: u64 } + Inner2{ x: u64, y: u64 } + } + + +} + +//# publish +module 0x42::m2 { + + use 0x42::m1::Result; + use 0x42::m1::E; + use 0x42::m1::Inner; + + public fun test_pack_unpack_result_ok() { + let result = Result::Ok(42); + assert!(result == Result::Ok(42), 1); + let Result::Ok(ok) = result; + assert!(ok == 42, 2); + } + + public fun test_pack_unpack_result_err() { + let result: Result = Result::Err(7); + let Result::Err(err) = result; + assert!(err == 7, 3); + } + + public fun test_unpack_enum_e() { + let a = E::A { x: 100 }; + let b = E::B { x: 200 }; + + let E::A { x } = a; + assert!(x == 100, 4); + + let E::B { x: y } = b; + assert!(y == 200, 5); + } + + public fun test_unpack_inner() { + let v1 = Inner::Inner1 { x: 10 }; + let v2 = Inner::Inner2 { x: 20, y: 30 }; + + let val1 = match (v1) { + Inner::Inner1 { x } => x, + Inner::Inner2 { x, y } => x + y + }; + let val2 = match (v2) { + Inner::Inner1 { x } => x, + Inner::Inner2 { x, y } => x + y + }; + assert!(val1 == 10, 6); + assert!(val2 == 50, 7); + } + + +} + +//# run 0x42::m2::test_pack_unpack_result_ok + +//# run 0x42::m2::test_pack_unpack_result_err + +//# run 0x42::m2::test_unpack_enum_e + +//# run 0x42::m2::test_unpack_inner diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_variant_test.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_variant_test.exp new file mode 100644 index 0000000000000..181d9a34c8e5b --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_variant_test.exp @@ -0,0 +1,63 @@ +processed 9 tasks +task 0 lines 1-4: publish [module 0x42::m2 {] +task 1 lines 6-23: publish [module 0x42::m {] +task 2 lines 25-76: publish [module 0x42::m2 {] +Error: compilation errors: + bug: bytecode verification failed with unexpected status code `CALL_BORROWED_MUTABLE_REFERENCE_ERROR`: +Error message: none + ┌─ TEMPFILE2:60:7 + │ +60 │ Data2::V2{y, x} if (*y == 43) => { + │ ^^^^^^^^^^^^^^^ + │ + = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) + + +task 3 lines 78-78: run 0x42::m2::test_v1 +Error: Function execution failed with VMError: { + major_status: FUNCTION_RESOLUTION_FAILURE, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 4 lines 80-80: run 0x42::m2::test_v1v3 +Error: Function execution failed with VMError: { + major_status: FUNCTION_RESOLUTION_FAILURE, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 5 lines 82-82: run 0x42::m2::test_v1v3_ref +Error: Function execution failed with VMError: { + major_status: FUNCTION_RESOLUTION_FAILURE, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 6 lines 84-84: run 0x42::m2::test_v1_mut_borrow +Error: Function execution failed with VMError: { + major_status: FUNCTION_RESOLUTION_FAILURE, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 7 lines 86-86: run 0x42::m2::test_v2_mut_borrow_2 +Error: Function execution failed with VMError: { + major_status: FUNCTION_RESOLUTION_FAILURE, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 8 lines 88-88: run 0x42::m2::test_match_mut_borrow +Error: Function execution failed with VMError: { + major_status: FUNCTION_RESOLUTION_FAILURE, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_variant_test.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_variant_test.move new file mode 100644 index 0000000000000..4a1dd719d4cf7 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_enum_variant_test.move @@ -0,0 +1,88 @@ +//# publish +module 0x42::m2 { + +} + +//# publish +module 0x42::m { + + friend 0x42::m2; + + friend enum Data has drop { + V1{x: u64}, + V2{x: u64, y: bool} + V3 + } + + friend enum Data2 has drop { + V1{x: u64}, + V2{y: u64, x: u64} + V3 + } + +} + +//# publish +module 0x42::m2 { + + use 0x42::m::Data; + use 0x42::m::Data2; + + fun test_v1(): bool { + let d = Data::V1{x: 43}; + (d is V1) && (&d is V1|V3) + } + + fun test_v1v3(): bool { + let d = Data::V1{x: 43}; + let t = (d is V1|V3); + let d = Data::V3{}; + t && (d is V1|V3) + } + + fun test_v1v3_ref(): bool { + let d = Data::V1{x: 43}; + let t = (&d is V1|V3); + let d = Data::V3{}; + t && (&mut d is V1|V3) + } + + public fun test_v1_mut_borrow() { + let d = Data::V1{x: 43}; + let r = &mut d.x; + *r = 44; + assert!(d.x == 44, 1); + } + + public fun test_v2_mut_borrow_2() { + let d = Data2::V2{y: 43, x: 44}; + let r = &mut d.x; + *r = 45; + assert!(d.x == 45, 1); + } + + public fun test_match_mut_borrow() { + let d = Data2::V2{y: 43, x: 44}; + match (&mut d) { + Data2::V2{y, x} if (*y == 43) => { + *x = 45; + assert!(d.x == 45, 1); + }, + _ => {} + } + } + + +} + +//# run 0x42::m2::test_v1 + +//# run 0x42::m2::test_v1v3 + +//# run 0x42::m2::test_v1v3_ref + +//# run 0x42::m2::test_v1_mut_borrow + +//# run 0x42::m2::test_v2_mut_borrow_2 + +//# run 0x42::m2::test_match_mut_borrow diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_fv_struct_api.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_fv_struct_api.exp new file mode 100644 index 0000000000000..1568eff357797 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_fv_struct_api.exp @@ -0,0 +1,7 @@ +processed 6 tasks +task 0 lines 1-7: publish [module 0x42::m1 {] +task 1 lines 9-47: publish [module 0x42::m2 {] +task 2 lines 49-49: run 0x42::m2::try_direct_assignment_and_call +task 3 lines 51-51: run 0x42::m2::try_pass_to_apply +task 4 lines 53-53: run 0x42::m2::try_nested_wrapper +task 5 lines 55-55: run 0x42::m2::try_unpack_wrapper diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_fv_struct_api.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_fv_struct_api.move new file mode 100644 index 0000000000000..bc9fdc7e40418 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_fv_struct_api.move @@ -0,0 +1,55 @@ +//# publish +module 0x42::m1 { + public struct Predicate(|&T| bool) has copy, drop; + + public struct Holder(Predicate) has copy, drop; + +} + +//# publish +module 0x42::m2 { + use 0x42::m1::Predicate; + use 0x42::m1::Holder; + + fun apply_pred(p: Predicate, val: u64): bool { + p(&val) + } + + fun apply_holder(h: Holder, val: u64): bool { + let Holder(p) = h; + p(&val) + } + + fun try_direct_assignment_and_call() { + let p: Predicate = |x| *x < 100; + assert!(p(&99), 1); + assert!(!p(&101), 2); + } + + fun try_pass_to_apply() { + let p: Predicate = |x| *x % 2 == 0; + assert!(apply_pred(p, 4), 5); + assert!(!apply_pred(p, 5), 6); + } + + fun try_nested_wrapper() { + let h = Holder(|x| *x == 42); + assert!(apply_holder(h, 42), 7); + assert!(!apply_holder(h, 99), 8); + } + + fun try_unpack_wrapper() { + let p: Predicate = |x| *x != 0; + let Predicate(f) = p; + assert!(f(&1), 9); + assert!(!f(&0), 10); + } +} + +//# run 0x42::m2::try_direct_assignment_and_call + +//# run 0x42::m2::try_pass_to_apply + +//# run 0x42::m2::try_nested_wrapper + +//# run 0x42::m2::try_unpack_wrapper diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_positional_field_api.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_positional_field_api.exp new file mode 100644 index 0000000000000..2909f56c9d285 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_positional_field_api.exp @@ -0,0 +1,78 @@ +processed 10 tasks +task 0 lines 1-10: publish [module 0x42::m1 {] +task 1 lines 12-93: publish [module 0x42::m2 {] +Error: compilation errors: + bug: bytecode verification failed with unexpected status code `CALL_BORROWED_MUTABLE_REFERENCE_ERROR`: +Error message: none + ┌─ TEMPFILE1:75:13 + │ +75 │ let NestedPair(p, w) = &mut np; + │ ^^^^^^^^^^^^^^^^ + │ + = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) + + +task 2 lines 96-96: run 0x42::m2::test_borrow_pair_fields +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 3 lines 98-98: run 0x42::m2::test_borrow_wrapper_field +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 4 lines 100-100: run 0x42::m2::test_borrow_nested_pair_fields +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 5 lines 102-102: run 0x42::m2::test_borrow_vecwrap_element +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 6 lines 104-104: run 0x42::m2::test_mut_borrow_pair +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 7 lines 106-106: run 0x42::m2::test_mut_borrow_vecwrap_element +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 8 lines 108-108: run 0x42::m2::test_mut_borrow_nestedpair +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 9 lines 110-110: run 0x42::m2::test_mut_borrow_nestedpair_2 +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_positional_field_api.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_positional_field_api.move new file mode 100644 index 0000000000000..10aa65fcae5e1 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_positional_field_api.move @@ -0,0 +1,110 @@ +//# publish +module 0x42::m1 { + public struct Pair(u64, bool) has copy, drop; + + public struct Wrapper(T) has drop; + + public struct NestedPair(Pair, Wrapper) has drop; + + public struct VecWrap(vector) has drop; +} + +//# publish +module 0x42::m2 { + use 0x42::m1::{Pair, Wrapper, NestedPair, VecWrap}; + + public fun test_borrow_pair_fields() { + let p = Pair(42, true); + let x = &p.0; + let y = &p.1; + assert!(*x == 42, 0); + assert!(*y, 1); + } + + public fun test_borrow_wrapper_field() { + let w = Wrapper(100); + let inner = &w.0; + assert!(*inner == 100, 2); + } + + public fun test_borrow_nested_pair_fields() { + let p = Pair(1, false); + let w = Wrapper(99); + let np = NestedPair(p, w); + + let inner_pair_0 = &np.0.0; + let inner_pair_1 = &np.0.1; + let wrapped_val = &np.1.0; + + assert!(*inner_pair_0 == 1, 3); + assert!(!*inner_pair_1, 4); + assert!(*wrapped_val == 99, 5); + } + + public fun test_borrow_vecwrap_element() { + let v = VecWrap(vector[10, 20, 30]); + let first = &v.0[0]; + let second = &v.0[1]; + assert!(*first == 10, 6); + assert!(*second == 20, 7); + } + + public fun test_mut_borrow_pair() { + let p = Pair(7, false); + let r = &mut p; + let r0 = &mut r.0; + *r0 = 8; + assert!(p.0 == 8, 8); + } + + public fun test_mut_borrow_vecwrap_element() { + let v = VecWrap(vector[1, 2, 3]); + let r = &mut v; + let el = &mut r.0[1]; + *el = 10; + assert!(v.0[1] == 10, 9); + } + + public fun test_mut_borrow_nestedpair() { + let p = Pair(0, true); + let w = Wrapper(77); + let np = NestedPair(p, w); + let r = &mut np; + let b1 = &mut r.0.0; + *b1 = 123; + let b2 = &mut r.1.0; + *b2 = 456; + assert!(np.0.0 == 123, 10); + assert!(np.1.0 == 456, 11); + } + + public fun test_mut_borrow_nestedpair_2() { + let p = Pair(0, true); + let w = Wrapper(77); + let np = NestedPair(p, w); + let NestedPair(p, w) = &mut np; + let Pair(b1, _) = p; + let Wrapper(b2) = w; + *b1 = 123; + *b2 = 456; + assert!(np.0.0 == 123, 10); + assert!(np.1.0 == 456, 11); + } +} + + +//# run 0x42::m2::test_borrow_pair_fields + +//# run 0x42::m2::test_borrow_wrapper_field + +//# run 0x42::m2::test_borrow_nested_pair_fields + +//# run 0x42::m2::test_borrow_vecwrap_element + +//# run 0x42::m2::test_mut_borrow_pair + +//# run 0x42::m2::test_mut_borrow_vecwrap_element + +//# run 0x42::m2::test_mut_borrow_nestedpair + +//# run 0x42::m2::test_mut_borrow_nestedpair_2 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_positional_pack_unpack_api.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_positional_pack_unpack_api.exp new file mode 100644 index 0000000000000..bc9b90521f5d0 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_positional_pack_unpack_api.exp @@ -0,0 +1,9 @@ +processed 8 tasks +task 0 lines 1-10: publish [module 0x42::m1 {] +task 1 lines 12-69: publish [module 0x42::m2 {] +task 2 lines 71-71: run 0x42::m2::try_pack_unpack_pair +task 3 lines 73-73: run 0x42::m2::try_pack_unpack_wrapper +task 4 lines 75-75: run 0x42::m2::try_nested_pair_unpack +task 5 lines 77-77: run 0x42::m2::try_vecwrap_unpack +task 6 lines 79-79: run 0x42::m2::try_unpack_from_return +task 7 lines 81-81: run 0x42::m2::try_pass_as_arg diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_positional_pack_unpack_api.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_positional_pack_unpack_api.move new file mode 100644 index 0000000000000..4a652ad676f2d --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_positional_pack_unpack_api.move @@ -0,0 +1,81 @@ +//# publish +module 0x42::m1 { + public struct Pair(u64, bool) has copy, drop; + + public struct Wrapper(T) has drop; + + public struct NestedPair(Pair, Wrapper) has drop; + + public struct VecWrap(vector) has drop; +} + +//# publish +module 0x42::m2 { + use 0x42::m1::Pair; + use 0x42::m1::Wrapper; + use 0x42::m1::NestedPair; + use 0x42::m1::VecWrap; + + public fun try_pack_unpack_pair() { + let p = Pair(1, true); + let Pair(x, y) = p; + assert!(x == 1, 1); + assert!(y == true, 2); + } + + public fun try_pack_unpack_wrapper() { + let w = Wrapper(100); + let Wrapper(x) = w; + assert!(x == 100, 3); + } + + public fun try_nested_pair_unpack() { + let p = Pair(5, false); + let w = Wrapper(vector[42, 43]); + let n = NestedPair(p, w); + let NestedPair(Pair(a, b), Wrapper(v)) = n; + assert!(a == 5, 4); + assert!(b == false, 5); + assert!(v[1] == 43, 6); + } + + public fun try_vecwrap_unpack() { + let vw = VecWrap(vector[10, 20, 30]); + let VecWrap(v) = vw; + assert!(v[0] == 10, 7); + assert!(v[2] == 30, 8); + } + + public fun try_return_positional(): Pair { + Pair(77, false) + } + + public fun try_unpack_from_return() { + let Pair(x, y) = try_return_positional(); + assert!(x == 77, 9); + assert!(y == false, 10); + } + + public fun use_as_param(p: Pair) { + let Pair(a, b) = p; + assert!(a == 88, 11); + assert!(b == true, 12); + } + + public fun try_pass_as_arg() { + let p = Pair(88, true); + use_as_param(p); + } +} + +//# run 0x42::m2::try_pack_unpack_pair + +//# run 0x42::m2::try_pack_unpack_wrapper + +//# run 0x42::m2::try_nested_pair_unpack + +//# run 0x42::m2::try_vecwrap_unpack + +//# run 0x42::m2::try_unpack_from_return + +//# run 0x42::m2::try_pass_as_arg diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_struct_borrow_field_api.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_struct_borrow_field_api.exp new file mode 100644 index 0000000000000..1b1b9bc3ebd4c --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_struct_borrow_field_api.exp @@ -0,0 +1,62 @@ +processed 8 tasks +task 0 lines 1-12: publish [module 0x42::m1 {] +task 1 lines 14-99: publish [module 0x42::m2 {] +Error: compilation errors: + bug: bytecode verification failed with unexpected status code `CALL_BORROWED_MUTABLE_REFERENCE_ERROR`: +Error message: none + ┌─ TEMPFILE1:63:13 + │ +63 │ let S { f, g } = &mut s; + │ ^^^^^^^^^^ + │ + = please consider reporting this issue (see https://aptos.dev/en/build/smart-contracts/compiler_v2#reporting-an-issue) + + +task 2 lines 101-101: run 0x42::m2::try_immut_borrow_fields +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 3 lines 103-103: run 0x42::m2::try_immut_from_mut +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 4 lines 105-105: run 0x42::m2::try_mut_borrow_seq +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 5 lines 107-107: run 0x42::m2::try_immut_and_mut_diff_fields +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 6 lines 109-109: run 0x42::m2::try_reborrow_same_field_seq +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} +task 7 lines 111-111: run 0x42::m2::try_unpack_mut_ref +Error: Function execution failed with VMError: { + major_status: LINKER_ERROR, + sub_status: None, + location: undefined, + indices: [], + offsets: [], +} diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_struct_borrow_field_api.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_struct_borrow_field_api.move new file mode 100644 index 0000000000000..5a0d4daeee648 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_struct_borrow_field_api.move @@ -0,0 +1,111 @@ +//# publish +module 0x42::m1 { + + public struct S has drop { + f: u64, + g: T + } + + public struct T has store, copy, drop { + h: G + } +} + +//# publish +module 0x42::m2 { + + use 0x42::m1::{S, T}; + + public fun try_immut_borrow_fields() { + let t = T { h: 100 }; + let s = S { f: 200, g: t }; + let f = &s.f; + let h = &s.g.h; + assert!(*f == 200, 3); + assert!(*h == 100, 4); + } + + public fun try_immut_from_mut() { + let t = T { h: 5 }; + let s = S { f: 6, g: t }; + let r = &mut s; + let f = &r.f; + assert!(*f == 6, 5); + } + + public fun try_mut_borrow_seq() { + let t = T { h: 1 }; + let s = S { f: 2, g: t }; + let f = &mut s.f; + *f = *f + 10; + let h = &mut s.g.h; + *h = *h + 20; + assert!(s.f == 12, 7); + assert!(s.g.h == 21, 8); + } + + public fun try_immut_and_mut_diff_fields() { + let t = T { h: 30 }; + let s = S { f: 40, g: t }; + let f = &s.f; + assert!(*f == 40, 9); + let h = &mut s.g.h; + *h = *h + 1; + assert!(*h == 31, 10); + } + + public fun try_reborrow_same_field_seq() { + let t = T { h: 9 }; + let s = S { f: 8, g: t }; + let f = &mut s.f; + *f = 88; + let f2 = &mut s.f; + *f2 = *f2 + 1; + assert!(s.f == 89, 11); + } + + public fun try_unpack_mut_ref() { + let t = T { h: 9 }; + let s = S { f: 8, g: t }; + let S { f, g } = &mut s; + *f = 88; + g.h = 99; + assert!(s.f == 88, 11); + assert!(s.g.h == 99, 12); + let S { f: _, g } = &mut s; + g.h = 100; + assert!(g.h == 100, 14); + let S { f: _, g: T { h } } = &mut s; + *h = 101; + assert!(s.g.h == 101, 15); + let S { f, g: T { h: _ } } = &mut s; + *f = 101; + assert!(s.f == 101, 15); + } + + public fun try_unpack_ref() { + let t = T { h: 9 }; + let s = S { f: 8, g: t }; + let S { f, g } = &s; + assert!(*f == 8, 11); + assert!(g.h == 9, 12); + let S { f: _, g } = &s; + assert!(g.h == 9, 14); + let S { f: _, g: T { h } } = &s; + assert!(*h == 9, 15); + let S { f, g: T { h: _ } } = &s; + assert!(*f == 8, 15); + } +} + +//# run 0x42::m2::try_immut_borrow_fields + +//# run 0x42::m2::try_immut_from_mut + +//# run 0x42::m2::try_mut_borrow_seq + +//# run 0x42::m2::try_immut_and_mut_diff_fields + +//# run 0x42::m2::try_reborrow_same_field_seq + +//# run 0x42::m2::try_unpack_mut_ref diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_struct_pack_unpack_api.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_struct_pack_unpack_api.exp new file mode 100644 index 0000000000000..d3ab485a7cf58 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_struct_pack_unpack_api.exp @@ -0,0 +1,14 @@ +processed 13 tasks +task 0 lines 1-31: publish [module 0x42::m1 {] +task 1 lines 33-42: publish [module 0x42::m3 {] +task 2 lines 44-129: publish [module 0x42::m2 {] +task 3 lines 131-131: run 0x42::m2::try_pack +task 4 lines 133-133: run 0x42::m2::try_pack_vector +task 5 lines 135-135: run 0x42::m2::try_unpack +task 6 lines 137-137: run 0x42::m2::try_unpack_with_let_ignore +task 7 lines 139-139: run 0x42::m2::try_nested_pack +task 8 lines 141-141: run 0x42::m2::try_unpack_nested +task 9 lines 143-143: run 0x42::m2::try_return_struct +task 10 lines 145-145: run 0x42::m2::try_pass_struct_as_arg +task 11 lines 147-147: run 0x42::m2::try_pack_unpack_phantom +task 12 lines 149-149: run 0x42::m2::try_pack_S3 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_struct_pack_unpack_api.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_struct_pack_unpack_api.move new file mode 100644 index 0000000000000..a44fb4a0f9adf --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/structs_visibility/test_struct_pack_unpack_api.move @@ -0,0 +1,149 @@ +//# publish +module 0x42::m1 { + + public struct S has drop { + f: u64, + g: T + } + + public struct T has store, copy, drop { + h: G + } + + public struct V has store, copy, drop { + items: vector + } + + public struct Nested has store, copy, drop { + inner: T> + } + + public struct P has drop { + p: u64 + } + + struct Inner has drop { + t: T + } + + public struct NoFields has drop {} + +} + +//# publish +module 0x42::m3 { + use 0x42::m1::T; + + public struct S has drop { + f: u64, + g: T + } + +} + +//# publish +module 0x42::m2 { + + use 0x42::m1::{S, T, V, Nested, P, Inner, NoFields}; + use 0x42::m3::S as S3; + + public fun try_pack_unpack_no_fields() { + let no_fields = NoFields {}; + let NoFields {} = no_fields; + } + + public fun try_pack_unpack_phantom() { + let p = P> { p: 42 }; + assert!(p.p == 42, 1); + let P { p } = p; + assert!(p == 42, 4); + } + + public fun try_pack() { + let t = T { h: 42 }; + assert!(t.h == 42, 1); + let s = S { f: 43, g: t }; + assert!(s.f == 43, 2); + } + + public fun try_pack_vector() { + let t = T { h: vector[42] }; + assert!(t.h[0] == 42, 3); + } + + public fun try_unpack() { + let s = S { f: 43, g: T { h: 42 } }; + let S { f, g: T { h } } = s; + assert!(f == 43, 4); + assert!(h == 42, 5); + } + + public fun try_unpack_with_let_ignore() { + let s = S { f: 100, g: T { h: 7 } }; + let S { f, g: _ } = s; + assert!(f == 100, 6); + } + + public fun try_nested_pack() { + let v = V { items: vector[1, 2, 3] }; + let nested = Nested { inner: T { h: v } }; + assert!(nested.inner.h.items[2] == 3, 7); + } + + public fun try_unpack_nested() { + let s = Nested { + inner: T { h: V { items: vector[10, 20] } } + }; + let Nested { inner: T { h: V { items } } } = s; + assert!(items[0] == 10, 8); + assert!(items[1] == 20, 9); + } + + public fun return_struct(): S { + S { f: 77, g: T { h: 88 } } + } + + public fun try_return_struct() { + let s = return_struct(); + let S { f, g: T { h } } = s; + assert!(f == 77, 10); + assert!(h == 88, 11); + } + + public fun take_struct(s: S>) { + assert!(s.g.h[0] == 255, 12); + } + + public fun try_pass_struct_as_arg() { + let s = S { f: 1, g: T { h: vector[255] } }; + take_struct(s); + } + + public fun try_pack_S3() { + let t = T { h: 42 }; + assert!(t.h == 42, 1); + let s = S3 { f: 43, g: t }; + assert!(s.f == 43, 13); + assert!(s.g.h == 42, 14); + } +} + +//# run 0x42::m2::try_pack + +//# run 0x42::m2::try_pack_vector + +//# run 0x42::m2::try_unpack + +//# run 0x42::m2::try_unpack_with_let_ignore + +//# run 0x42::m2::try_nested_pack + +//# run 0x42::m2::try_unpack_nested + +//# run 0x42::m2::try_return_struct + +//# run 0x42::m2::try_pass_struct_as_arg + +//# run 0x42::m2::try_pack_unpack_phantom + +//# run 0x42::m2::try_pack_S3 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/tests.rs b/third_party/move/move-compiler-v2/transactional-tests/tests/tests.rs index b3a0c226aa4eb..82e878307d50b 100644 --- a/third_party/move/move-compiler-v2/transactional-tests/tests/tests.rs +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/tests.rs @@ -40,6 +40,7 @@ const COMMON_EXCLUSIONS: &[&str] = &[ "/no-access-check/", "/no-recursive-type-check/", "/testing-constant/", + "/structs_visibility/", ]; /// Note that any config which has different output for a test directory @@ -101,7 +102,7 @@ const TEST_CONFIGS: &[TestConfig] = &[ experiments: &[(Experiment::OPTIMIZE, true)], language_version: LanguageVersion::V1, include: &["/operator_eval/"], - exclude: &[], + exclude: &["/structs_visibility/"], cross_compile: false, }, TestConfig { @@ -110,7 +111,7 @@ const TEST_CONFIGS: &[TestConfig] = &[ experiments: &[(Experiment::OPTIMIZE, true)], language_version: LanguageVersion::latest(), include: &["/operator_eval/"], - exclude: &[], + exclude: &["/structs_visibility/"], cross_compile: true, }, TestConfig { @@ -119,7 +120,7 @@ const TEST_CONFIGS: &[TestConfig] = &[ experiments: &[(Experiment::RECURSIVE_TYPE_CHECK, false)], language_version: LanguageVersion::latest(), include: &["/no-recursive-check/"], - exclude: &[], + exclude: &["/structs_visibility/"], cross_compile: false, }, TestConfig { @@ -128,7 +129,7 @@ const TEST_CONFIGS: &[TestConfig] = &[ experiments: &[(Experiment::ACCESS_CHECK, false)], language_version: LanguageVersion::latest(), include: &["/no-access-check/"], - exclude: &[], + exclude: &["/structs_visibility/"], cross_compile: false, }, TestConfig { @@ -137,6 +138,15 @@ const TEST_CONFIGS: &[TestConfig] = &[ experiments: &[(Experiment::RECURSIVE_TYPE_CHECK, false)], language_version: LanguageVersion::latest(), include: &["/no-recursive-type-check/"], + exclude: &["/structs_visibility/"], + cross_compile: false, + }, + TestConfig { + name: "public-struct", + runner: |p| run(p, get_config_by_name("public-struct")), + experiments: &[], + language_version: LanguageVersion::latest(), + include: &["/structs_visibility/"], exclude: &[], cross_compile: false, }, @@ -146,7 +156,7 @@ const TEST_CONFIGS: &[TestConfig] = &[ experiments: &[(Experiment::COMPILE_FOR_TESTING, true)], language_version: LanguageVersion::latest(), include: &["/testing-constant/"], - exclude: &[], + exclude: &["/structs_visibility/"], cross_compile: false, }, TestConfig { @@ -155,7 +165,7 @@ const TEST_CONFIGS: &[TestConfig] = &[ experiments: &[(Experiment::COMPILE_FOR_TESTING, false)], language_version: LanguageVersion::latest(), include: &["/testing-constant/"], - exclude: &[], + exclude: &["/structs_visibility/"], cross_compile: false, }, ]; @@ -181,6 +191,7 @@ const SEPARATE_BASELINE: &[&str] = &[ "no-v1-comparison/assert_one.move", "no-v1-comparison/closures/reentrancy", "no-v1-comparison/closures/reentrancy", + "no-v1-comparison/structs_visibility/migrated_tests/public_enum_field_select.move", "control_flow/for_loop_non_terminating.move", "control_flow/for_loop_nested_break.move", "evaluation_order/lazy_assert.move", diff --git a/third_party/move/move-model/src/builder/module_builder.rs b/third_party/move/move-model/src/builder/module_builder.rs index 94bce53be1eef..be6da583b05d4 100644 --- a/third_party/move/move-model/src/builder/module_builder.rs +++ b/third_party/move/move-model/src/builder/module_builder.rs @@ -3617,6 +3617,7 @@ impl ModuleBuilder<'_, '_> { is_native: entry.is_native, visibility: entry.visibility, has_package_visibility: self.package_structs.contains(&entry.struct_id), + is_empty_struct: entry.is_empty_struct, }; struct_data.insert(StructId::new(name.symbol), data); if entry.visibility != Visibility::Private diff --git a/third_party/move/move-model/src/model.rs b/third_party/move/move-model/src/model.rs index 28b889af37a94..6ae0a06acbe80 100644 --- a/third_party/move/move-model/src/model.rs +++ b/third_party/move/move-model/src/model.rs @@ -1667,9 +1667,12 @@ impl GlobalEnv { } for idx in 0..module.function_defs.len() { let def_idx = FunctionDefinitionIndex(idx as u16); + let definition = module.function_def_at(def_idx); + let definition_view = FunctionDefinitionView::new(&module, definition); let handle_idx = module.function_def_at(def_idx).function; let handle = module.function_handle_at(handle_idx); let view = FunctionHandleView::new(&module, handle); + let name_str = view.name().as_str(); let fun_id = if name_str.starts_with(SCRIPT_BYTECODE_FUN_NAME) { // This is a pseudo script module, which has exactly one function. Determine @@ -1686,34 +1689,77 @@ impl GlobalEnv { }; // While releasing any mutation, compute the used/called functions if needed. - let fun_data = &self.module_data[module_id.to_usize()] - .function_data - .get(&fun_id) - .unwrap(); - let used_funs = if fun_data.used_funs.is_none() { - Some(self.get_used_funs_from_bytecode(&module, def_idx)) + let (used_funs, called_funs) = if let Some(fun_data) = self.module_data + [module_id.to_usize()] + .function_data + .get(&fun_id) + { + let used_funs = if fun_data.used_funs.is_none() { + Some(self.get_used_funs_from_bytecode(&module, def_idx)) + } else { + None + }; + let called_funs = if fun_data.called_funs.is_none() { + Some(self.get_called_funs_from_bytecode(&module, def_idx)) + } else { + None + }; + (used_funs, called_funs) } else { - None + let used_funs = Some(self.get_used_funs_from_bytecode(&module, def_idx)); + let called_funs = Some(self.get_called_funs_from_bytecode(&module, def_idx)); + (used_funs, called_funs) }; - let called_funs = if fun_data.called_funs.is_none() { - Some(self.get_called_funs_from_bytecode(&module, def_idx)) - } else { - None + let for_public_structs = self.language_version().language_version_for_public_struct(); + let (default_loc, fun_source_map_def_loc_opt) = { + // only immutable borrow here + let mod_data_imm = &self.module_data[module_id.0 as usize]; + let default_loc = mod_data_imm.loc.clone(); + let def_loc = mod_data_imm + .source_map + .as_ref() + .and_then(|sm| sm.get_function_source_map(def_idx).ok()) + .map( + |s: &move_bytecode_source_map::source_map::FunctionSourceMap| { + s.definition_location + }, + ); + (default_loc, def_loc) }; + let loc = fun_source_map_def_loc_opt + .map(|l| self.to_loc(&l)) + .unwrap_or(default_loc); + let name = self.symbol_pool.make(name_str); let mod_data = &mut self.module_data[module_id.0 as usize]; - if let Some(fun_data) = mod_data.function_data.get_mut(&fun_id) { - fun_data.def_idx = Some(def_idx); - fun_data.handle_idx = Some(handle_idx); - mod_data.function_idx_to_id.insert(def_idx, fun_id); - if let Some(used_funs) = used_funs { - fun_data.used_funs = Some(used_funs); - } - if let Some(called_funs) = called_funs { - fun_data.called_funs = Some(called_funs); - } + + let fun_data = if let Some(fun_data) = mod_data.function_data.get_mut(&fun_id) { + fun_data + } else if for_public_structs { + let entry = mod_data + .function_data + .entry(fun_id) + .or_insert_with(|| FunctionData::new(name, loc)); + entry.visibility = definition_view.visibility(); + entry.is_native = definition_view.is_native(); + entry.kind = if definition_view.is_entry() { + FunctionKind::Entry + } else { + FunctionKind::Regular + }; + entry } else { - panic!("attaching mismatching bytecode module") + panic!("attaching mismatching bytecode module"); + }; + + fun_data.def_idx = Some(def_idx); + fun_data.handle_idx = Some(handle_idx); + mod_data.function_idx_to_id.insert(def_idx, fun_id); + if let Some(used_funs) = used_funs { + fun_data.used_funs = Some(used_funs); + } + if let Some(called_funs) = called_funs { + fun_data.called_funs = Some(called_funs); } } let used_modules = self.get_used_modules_from_bytecode(&module); @@ -1948,6 +1994,7 @@ impl GlobalEnv { is_native: false, visibility: Visibility::Private, has_package_visibility: false, + is_empty_struct: false, } } @@ -3788,6 +3835,9 @@ pub struct StructData { /// Whether this struct has package visibility before the transformation. /// Invariant: when true, visibility is always friend. pub(crate) has_package_visibility: bool, + + /// Whether this struct is originally empty + pub is_empty_struct: bool, } impl StructData { @@ -3806,6 +3856,7 @@ impl StructData { is_native: false, visibility: Visibility::Private, has_package_visibility: false, + is_empty_struct: false, } } } @@ -3832,6 +3883,11 @@ impl<'env> StructEnv<'env> { self.module_env.env } + /// Returns true if this struct is originally empty + pub fn is_empty_struct(&self) -> bool { + self.data.is_empty_struct + } + /// Returns the name of this struct. pub fn get_name(&self) -> Symbol { self.data.name diff --git a/third_party/move/move-model/src/well_known.rs b/third_party/move/move-model/src/well_known.rs index c9cc893ee4d78..1ea721f00d42c 100644 --- a/third_party/move/move-model/src/well_known.rs +++ b/third_party/move/move-model/src/well_known.rs @@ -25,6 +25,13 @@ pub fn is_verify_only_attribute_name(s: &str) -> bool { s == "verify_only" } +// For public struct/enum APIs +pub const PUBLIC_STRUCT_DELIMITER: &str = "$"; +pub const PACK: &str = "pack"; +pub const UNPACK: &str = "unpack"; +pub const TEST_VARIANT: &str = "test_variant"; +pub const PARAM_NAME: &str = "_s"; + pub const VECTOR_MODULE: &str = "vector"; pub const VECTOR_BORROW_MUT: &str = "vector::borrow_mut"; pub const EVENT_EMIT_EVENT: &str = "event::emit_event";