diff --git a/sway-core/src/asm_generation/finalized_asm.rs b/sway-core/src/asm_generation/finalized_asm.rs index 8f32505e57a..c3304b4fd53 100644 --- a/sway-core/src/asm_generation/finalized_asm.rs +++ b/sway-core/src/asm_generation/finalized_asm.rs @@ -4,6 +4,7 @@ use super::{ fuel::{checks, data_section::DataSection}, ProgramABI, ProgramKind, }; +use crate::asm_generation::fuel::data_section::{DataId, Datum, Entry}; use crate::asm_lang::allocated_ops::{AllocatedOp, AllocatedOpcode}; use crate::decl_engine::DeclRefFunction; use crate::source_map::SourceMap; @@ -246,8 +247,64 @@ fn to_bytecode_mut( } } } + if build_config.print_bytecode { - println!("{}", data_section); + println!(".data_section:"); + + let offset = bytecode.len(); + + fn print_entry(indentation: usize, offset: usize, pair: &Entry) { + print!("{}{:#010x} ", " ".repeat(indentation), offset); + + match &pair.value { + Datum::Byte(w) => println!(".byte i{w}, as hex {w:02X}"), + Datum::Word(w) => { + println!(".word i{w}, as hex be bytes ({:02X?})", w.to_be_bytes()) + } + Datum::ByteArray(bs) => { + print!(".bytes as hex ({bs:02X?}), len i{}, as ascii \"", bs.len()); + + for b in bs { + print!( + "{}", + if *b == b' ' || b.is_ascii_graphic() { + *b as char + } else { + '.' + } + ); + } + println!("\""); + } + Datum::Slice(bs) => { + print!(".slice as hex ({bs:02X?}), len i{}, as ascii \"", bs.len()); + + for b in bs { + print!( + "{}", + if *b == b' ' || b.is_ascii_graphic() { + *b as char + } else { + '.' + } + ); + } + println!("\""); + } + Datum::Collection(els) => { + println!(".collection"); + for e in els { + print_entry(indentation + 1, offset, e); + } + } + }; + } + + for (i, entry) in data_section.value_pairs.iter().enumerate() { + let entry_offset = data_section.data_id_to_offset(&DataId(i as u32)); + print_entry(indentation, offset + entry_offset, entry); + } + println!(";; --- END OF TARGET BYTECODE ---\n"); } diff --git a/sway-core/src/asm_generation/fuel/allocated_abstract_instruction_set.rs b/sway-core/src/asm_generation/fuel/allocated_abstract_instruction_set.rs index 38466cf3edc..bf0627de013 100644 --- a/sway-core/src/asm_generation/fuel/allocated_abstract_instruction_set.rs +++ b/sway-core/src/asm_generation/fuel/allocated_abstract_instruction_set.rs @@ -121,14 +121,14 @@ impl AllocatedAbstractInstructionSet { new_ops.push(AllocatedAbstractOp { opcode: Either::Left(AllocatedOpcode::PSHL(mask_l)), comment: "Save registers 16..40".into(), - owning_span: None, + owning_span: op.owning_span.clone(), }); } if mask_h.value != 0 { new_ops.push(AllocatedAbstractOp { opcode: Either::Left(AllocatedOpcode::PSHH(mask_h)), comment: "Save registers 40..64".into(), - owning_span: None, + owning_span: op.owning_span.clone(), }); } } @@ -147,14 +147,14 @@ impl AllocatedAbstractInstructionSet { new_ops.push(AllocatedAbstractOp { opcode: Either::Left(AllocatedOpcode::POPH(mask_h)), comment: "Restore registers 40..64".into(), - owning_span: None, + owning_span: op.owning_span.clone(), }); } if mask_l.value != 0 { new_ops.push(AllocatedAbstractOp { opcode: Either::Left(AllocatedOpcode::POPL(mask_l)), comment: "Restore registers 16..40".into(), - owning_span: None, + owning_span: op.owning_span.clone(), }); } } diff --git a/sway-core/src/asm_generation/fuel/functions.rs b/sway-core/src/asm_generation/fuel/functions.rs index fed3a7ed0a3..5939535c716 100644 --- a/sway-core/src/asm_generation/fuel/functions.rs +++ b/sway-core/src/asm_generation/fuel/functions.rs @@ -274,8 +274,8 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { function.get_name(self.context) ); - self.cur_bytecode.push(match span { - Some(span) => Op::jump_label_comment(start_label, span, comment), + self.cur_bytecode.push(match &span { + Some(span) => Op::jump_label_comment(start_label, span.clone(), comment), None => Op::unowned_jump_label_comment(start_label, comment), }); @@ -285,7 +285,7 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { self.cur_bytecode.push(Op { opcode: Either::Right(OrganizationalOp::PushAll(start_label)), comment: "save all regs".to_owned(), - owning_span: None, + owning_span: span.clone(), }); } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs index 85cc2ee0634..7abdfbc54a3 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs @@ -112,7 +112,7 @@ impl ty::TyMatchExpression { let typed_if_exp = handler.scope( |handler| match &*ctx.engines().te().get(self.value_type_id) { - TypeInfo::StringSlice => self.desugar_to_radix_tree(ctx), + TypeInfo::StringSlice => self.desugar_to_radix_trie(ctx), _ => self.desugar_to_typed_if_expression(instantiate, ctx, handler), }, )?; @@ -120,7 +120,7 @@ impl ty::TyMatchExpression { Ok(typed_if_exp) } - fn desugar_to_radix_tree( + fn desugar_to_radix_trie( &self, mut ctx: TypeCheckContext<'_>, ) -> Result { @@ -220,6 +220,7 @@ impl ty::TyMatchExpression { // Now create the outer expression checking the size of the string slice let mut block = wildcard_return_expr.clone(); + for ((k, _), trie) in match_arms_by_size.into_iter().zip(tries.into_iter()) { if RADIX_TREE_DEBUG { println!("if str.len() == {k}"); @@ -277,7 +278,7 @@ impl ty::TyMatchExpression { }, Span::dummy(), )), - whole_block_span: Span::dummy(), + whole_block_span: self.span.clone(), }; let then_node = self @@ -297,13 +298,13 @@ impl ty::TyMatchExpression { condition: Box::new(TyExpression { expression, return_type: bool_type_id, - span: Span::dummy(), + span: self.span.clone(), }), then: Box::new(then_node), r#else: Some(Box::new(block)), }, return_type: branch_return_type_id, - span: Span::dummy(), + span: self.span.clone(), }; } @@ -397,7 +398,7 @@ impl ty::TyMatchExpression { span: Span::dummy(), }; - let expr = self.generate_radrix_tree_code( + let expr = self.generate_radrix_trie_code( matched_value, packed_strings, &packed_strings_expr, @@ -415,7 +416,7 @@ impl ty::TyMatchExpression { } #[allow(clippy::too_many_arguments)] - fn generate_radrix_tree_code( + fn generate_radrix_trie_code( &self, matched_value: &TyExpression, packed_strings: &str, @@ -460,7 +461,7 @@ impl ty::TyMatchExpression { ); } - let then_node = self.generate_radrix_tree_code( + let then_node = self.generate_radrix_trie_code( matched_value, packed_strings, packed_strings_expr, diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_all/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_all/src/main.sw index fe9bf914c26..0a493b8bc16 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_all/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_all/src/main.sw @@ -18,6 +18,7 @@ fn inc_i(ref mut i: u64) -> Struct { Struct { x: 21, y: 21, z: 1 } } +#[inline(never)] fn return_match_on_str_slice(param: str) -> u64 { match param { "get_a" => { 1u64 }, @@ -28,5 +29,89 @@ fn return_match_on_str_slice(param: str) -> u64 { } fn main() { + let x = match 8 { + 7 => { 4 }, + 9 => { 5 }, + 8 => { 42 }, + _ => { 100 }, + }; + assert(x == 42); + + let a = 5; + let x = match a { + 7 => { 4 }, + 5 => { 42 }, + _ => { 24 }, + }; + assert(x == 42); + + let a = 5; + let x = match a { + 7 | 8 | 9 => { 4 }, + 3 | 4 | 5 => { 42 }, + _ => { 24 }, + }; + assert(x == 42); + + // Test side effects. `inc_i` must be called exactly once. + let mut i = 0; + let x = match inc_i(i) { + Struct { x, y, z: 0 } => x + y, + Struct { x, y, z: 1 } => x + y, + _ => 24, + }; + assert(i == 11); + assert(x == 42); + + // Test match expressions with just one arm. + let e = Enum::A(42); + + let x = match e { + _ => 9999, + }; + assert(x == 9999); + + let e = Enum::B(42); + let x = match e { + Enum::A(x) | Enum::B(x) => x, + }; + assert(x == 42); + + let x = match e { + Enum::A(_) | Enum::B(_) => 9999, + }; + assert(x == 9999); + + let e = 42u64; + let x = match e { + y => y, + }; + assert(x == 42); + + let mut i = 0; + match e { + _ => { + let _s = inc_i(i); + } + }; + assert(i == 11); + + let r = match 42 { + 0 => { 24 }, + foo => { foo }, + }; + assert(r == 42); + + // string slice assert(return_match_on_str_slice("") == 1000); + assert(return_match_on_str_slice("g") == 1000); + assert(return_match_on_str_slice("ge") == 1000); + assert(return_match_on_str_slice("get") == 1000); + assert(return_match_on_str_slice("get_") == 1000); + assert(return_match_on_str_slice("get_a") == 1); + assert(return_match_on_str_slice("get_a_") == 1000); + assert(return_match_on_str_slice("get_a_b") == 2); + assert(return_match_on_str_slice("get_b") == 3); + assert(return_match_on_str_slice("get_c") == 1000); } +