From 60acf33c6a9b345d9c493f7c2c476b36632461ca Mon Sep 17 00:00:00 2001 From: xunilrj Date: Tue, 5 Dec 2023 17:52:24 +0000 Subject: [PATCH] auto impl for AbiEncode --- .../asm_generation/fuel/fuel_asm_builder.rs | 77 +++-- sway-core/src/ir_generation/function.rs | 1 + .../ast_node/declaration/declaration.rs | 283 ++++++++++-------- .../ast_node/expression/typed_expression.rs | 1 + .../src/semantic_analysis/ast_node/mod.rs | 6 + .../src/semantic_analysis/namespace/items.rs | 9 +- .../src/semantic_analysis/namespace/module.rs | 4 + .../src/semantic_analysis/namespace/root.rs | 17 +- .../semantic_analysis/namespace/trait_map.rs | 11 +- sway-lib-core/src/codec.sw | 12 +- test/src/e2e_vm_tests/harness.rs | 12 +- .../should_pass/language/logging/src/main.sw | 6 +- 12 files changed, 286 insertions(+), 153 deletions(-) diff --git a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs index e5a811c588e..c70fa5548e1 100644 --- a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs +++ b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs @@ -1264,27 +1264,64 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { // If the type is a pointer then we use LOGD to log the data. First put the size into // the data section, then add a LW to get it, then add a LOGD which uses it. let log_ty = log_ty.get_pointee_type(self.context).unwrap(); - let size_in_bytes = log_ty.size(self.context).in_bytes(); + + // Slices arrive here as "ptr slice" because they are demoted. (see fn log_demotion) + let is_slice = log_ty.is_slice(self.context); - let size_reg = self.reg_seqr.next(); - self.immediate_to_reg( - size_in_bytes, - size_reg.clone(), - None, - "loading size for LOGD", - owning_span.clone(), - ); + if is_slice { + let ptr_reg = self.reg_seqr.next(); + let size_reg = self.reg_seqr.next(); + self.cur_bytecode.push(Op { + opcode: Either::Left(VirtualOp::LW( + ptr_reg.clone(), + log_val_reg.clone(), + VirtualImmediate12 { value: 0 }, + )), + owning_span: owning_span.clone(), + comment: "load slice ptr".into(), + }); + self.cur_bytecode.push(Op { + opcode: Either::Left(VirtualOp::LW( + size_reg.clone(), + log_val_reg.clone(), + VirtualImmediate12 { value: 1 }, + )), + owning_span: owning_span.clone(), + comment: "load slice size".into(), + }); + self.cur_bytecode.push(Op { + owning_span, + opcode: Either::Left(VirtualOp::LOGD( + VirtualRegister::Constant(ConstantRegister::Zero), + log_id_reg, + ptr_reg, + size_reg, + )), + comment: "log slice".into(), + }); + } else { + let size_in_bytes = log_ty.size(self.context).in_bytes(); + + let size_reg = self.reg_seqr.next(); + self.immediate_to_reg( + size_in_bytes, + size_reg.clone(), + None, + "loading size for LOGD", + owning_span.clone(), + ); - self.cur_bytecode.push(Op { - owning_span, - opcode: Either::Left(VirtualOp::LOGD( - VirtualRegister::Constant(ConstantRegister::Zero), - log_id_reg, - log_val_reg, - size_reg, - )), - comment: "".into(), - }); + self.cur_bytecode.push(Op { + owning_span: owning_span.clone(), + opcode: Either::Left(VirtualOp::LOGD( + VirtualRegister::Constant(ConstantRegister::Zero), + log_id_reg.clone(), + log_val_reg.clone(), + size_reg, + )), + comment: "log ptr".into(), + }); + } } Ok(()) @@ -1785,6 +1822,8 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { }) }) .ok_or_else(|| { + dbg!(value.with_context(self.context)); + todo!(); CompileError::Internal( "An attempt to get register for unknown Value.", Span::dummy(), diff --git a/sway-core/src/ir_generation/function.rs b/sway-core/src/ir_generation/function.rs index be1648f0567..c95c5d66ec8 100644 --- a/sway-core/src/ir_generation/function.rs +++ b/sway-core/src/ir_generation/function.rs @@ -911,6 +911,7 @@ impl<'eng> FnCompiler<'eng> { Some(log_ty) => { let span_md_idx = md_mgr.span_to_md(context, &span); + dbg!(log_ty, log_ty.as_string(context)); // The `log` instruction Ok(self .current_block diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs index e0cf2a175ea..1e317ae6793 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -1,13 +1,15 @@ +use std::collections::HashMap; + use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{Ident, Named, Span, Spanned}; use crate::{ - decl_engine::{DeclEngineInsert, DeclRef, ReplaceFunctionImplementingType}, + decl_engine::{DeclEngineInsert, DeclRef, ReplaceFunctionImplementingType, DeclEngineGet}, language::{ parsed, ty::{ self, TyAstNode, TyCodeBlock, TyDecl, TyExpression, TyFunctionDecl, - TyFunctionParameter, TyImplItem, TyIntrinsicFunctionKind, + TyFunctionParameter, TyImplItem, TyIntrinsicFunctionKind, TyStructExpressionField, VariableMutability, }, CallPath, QualifiedCallPath, }, @@ -26,7 +28,7 @@ fn auto_impl_abi_encode(handler: &Handler, ctx: &mut TypeCheckContext, decl: ty: let type_id = ctx .engines .te() - .insert(ctx.engines, TypeInfo::Struct(decl_ref), None); + .insert(ctx.engines, TypeInfo::Struct(decl_ref.clone()), None); let unit = ctx .engines @@ -39,131 +41,176 @@ fn auto_impl_abi_encode(handler: &Handler, ctx: &mut TypeCheckContext, decl: ty: None, ); - if let Some(buffer_type_id) = ctx.engines.de().get_structs_by_name( - &Ident::new_no_span("Buffer".into()) - ) { - let buffer_type_id = ctx.engines.te().insert(ctx.engines, TypeInfo::Custom { - qualified_call_path: QualifiedCallPath { - call_path: CallPath { - prefixes: vec![ - Ident::new_no_span("core".into()), - Ident::new_no_span("codec".into()), - ], - suffix: Ident::new_no_span("Buffer".into()), - is_absolute: false, - }, - qualified_path_root: None, + let struct_ref = ctx.engines().de().get(decl_ref.id()); + + let buffer_type_id = ctx.engines.te().insert(&ctx.engines, TypeInfo::Custom { + qualified_call_path: QualifiedCallPath { + call_path: CallPath { + prefixes: vec![ + Ident::new_no_span("core".into()), + Ident::new_no_span("codec".into()), + ], + suffix: Ident::new_no_span("Buffer".into()), + is_absolute: true }, - type_arguments: None, - root_type_id: None - }, None); - - let abi_encode_impl = ctx.engines.de().insert(TyFunctionDecl { - name: Ident::new_no_span("abi_encode".into()), - body: TyCodeBlock { - contents: vec![TyAstNode { - content: ty::TyAstNodeContent::Expression(TyExpression { - expression: ty::TyExpressionVariant::IntrinsicFunction( - TyIntrinsicFunctionKind { - kind: sway_ast::Intrinsic::Log, - arguments: vec![TyExpression { - expression: ty::TyExpressionVariant::Literal( - crate::language::Literal::U64(12), - ), - return_type: u64_type_id, - span: Span::dummy(), - }], - type_arguments: vec![], - span: Span::dummy(), - }, - ), - return_type: unit, - span: Span::dummy(), - }), - span: Span::dummy(), - }], - whole_block_span: Span::dummy(), - }, - parameters: vec![TyFunctionParameter { - name: Ident::new_no_span("self".into()), - is_reference: false, - is_mutable: false, - mutability_span: Span::dummy(), - type_argument: TypeArgument { - type_id, - initial_type_id: type_id, - span: Span::dummy(), - call_path_tree: None, - }, - }, TyFunctionParameter { - name: Ident::new_no_span("buffer".into()), - is_reference: true, - is_mutable: true, - mutability_span: Span::dummy(), - type_argument: TypeArgument { - type_id: buffer_type_id, - initial_type_id: buffer_type_id, - span: Span::dummy(), - call_path_tree: Some(crate::language::CallPathTree { - qualified_call_path: QualifiedCallPath { + qualified_path_root: None + }, + type_arguments: None, + root_type_id: None + }, None); + let buffer_type_id = ctx.resolve_type(handler, + buffer_type_id, + &Span::dummy(), + EnforceTypeArguments::No, + None + ).unwrap(); + + let abi_encode_body = struct_ref.fields.iter() + .map(|x| { + let abi_encode_ref = ctx.find_items_for_type(handler, x.type_argument.type_id, &[ + // Ident::new_no_span("core".into()), + // Ident::new_no_span("codec".into()), + ], &Ident::new_no_span("abi_encode".into())).unwrap().into_iter().next().unwrap(); + let abi_encode_ref = match abi_encode_ref { + ty::TyTraitItem::Fn(f) => f, + ty::TyTraitItem::Constant(_) => todo!(), + ty::TyTraitItem::Type(_) => todo!(), + }; + + TyAstNode { + content: ty::TyAstNodeContent::Expression( + TyExpression { + expression: ty::TyExpressionVariant::FunctionApplication { call_path: CallPath { prefixes: vec![ - Ident::new_no_span("core".into()), - Ident::new_no_span("codec".into()), + ], - suffix: Ident::new_no_span("Buffer".into()), + suffix: Ident::new_no_span("abi_encode".into()), is_absolute: false, }, - qualified_path_root: None, + contract_call_params: HashMap::default(), + arguments: vec![ + ( + Ident::new_no_span("self".into()), + TyExpression { + expression: ty::TyExpressionVariant::StructFieldAccess { + prefix: Box::new(TyExpression { + expression: ty::TyExpressionVariant::VariableExpression { + name: Ident::new_no_span("self".into()), + span: Span::dummy(), + mutability: VariableMutability::Immutable, + call_path: None + }, + return_type: unit.clone(), + span: Span::dummy() + }), + field_to_access: x.clone(), + field_instantiation_span: Span::dummy(), + resolved_type_of_parent: type_id.clone() + }, + return_type: unit, + span: Span::dummy() + } + ), + ( + Ident::new_no_span("buffer".into()), + TyExpression { + expression: ty::TyExpressionVariant::VariableExpression { + name: Ident::new_no_span("buffer".into()), + span: Span::dummy(), + mutability: VariableMutability::Mutable, + call_path: None + }, + return_type: buffer_type_id, + span: Span::dummy() + } + ) + ], + fn_ref: abi_encode_ref, + selector: None, + type_binding: None, + call_path_typeid: Some(type_id), + deferred_monomorphization: ctx.defer_monomorphization() }, - children: vec![] - }), - }, - }], - implementing_type: None, - span: Span::dummy(), - call_path: CallPath { - prefixes: vec![], - suffix: Ident::new_no_span("abi_encode".into()), - is_absolute: true, + return_type: unit, + span: Span::dummy() + } + ), + span: Span::dummy(), + } + }).collect::>(); + + let abi_encode_impl = ctx.engines.de().insert(TyFunctionDecl { + name: Ident::new_no_span("abi_encode".into()), + body: TyCodeBlock { + contents: abi_encode_body, + whole_block_span: Span::dummy(), + }, + parameters: vec![TyFunctionParameter { + name: Ident::new_no_span("self".into()), + is_reference: false, + is_mutable: false, + mutability_span: Span::dummy(), + type_argument: TypeArgument { + type_id, + initial_type_id: type_id, + span: Span::dummy(), + call_path_tree: None, }, - attributes: AttributesMap::default(), - type_parameters: vec![], - return_type: TypeArgument { - type_id: unit, - initial_type_id: unit, + }, TyFunctionParameter { + name: Ident::new_no_span("buffer".into()), + is_reference: true, + is_mutable: true, + mutability_span: Span::dummy(), + type_argument: TypeArgument { + type_id: buffer_type_id, + initial_type_id: buffer_type_id, span: Span::dummy(), call_path_tree: None, }, - visibility: crate::language::Visibility::Public, - is_contract_call: false, - purity: crate::language::Purity::Pure, - where_clause: vec![], - is_trait_method_dummy: false, - }); + }], + implementing_type: None, + span: Span::dummy(), + call_path: CallPath { + prefixes: vec![], + suffix: Ident::new_no_span("abi_encode".into()), + is_absolute: true, + }, + attributes: AttributesMap::default(), + type_parameters: vec![], + return_type: TypeArgument { + type_id: unit, + initial_type_id: unit, + span: Span::dummy(), + call_path_tree: None, + }, + visibility: crate::language::Visibility::Public, + is_contract_call: false, + purity: crate::language::Purity::Pure, + where_clause: vec![], + is_trait_method_dummy: false, + }); + - - let _ = ctx.namespace.implemented_traits.insert( - handler, - CallPath { - prefixes: vec![ - Ident::new_no_span("core".into()), - Ident::new_no_span("codec".into()), - ], - suffix: Ident::new_no_span("AbiEncode".into()), - is_absolute: true, - }, - vec![], - type_id, - &[TyImplItem::Fn(abi_encode_impl)], - &Span::dummy(), - None, - IsImplSelf::No, - IsExtendingExistingImpl::No, - ctx.engines, - ); - } - + let _ = ctx.namespace.implemented_traits.insert( + handler, + CallPath { + prefixes: vec![ + Ident::new_no_span("core".into()), + Ident::new_no_span("codec".into()), + ], + suffix: Ident::new_no_span("AbiEncode".into()), + is_absolute: true, + }, + vec![], + type_id, + &[TyImplItem::Fn(abi_encode_impl)], + &Span::dummy(), + None, + IsImplSelf::No, + IsExtendingExistingImpl::No, + ctx.engines, + ); } impl TyDecl { @@ -396,7 +443,9 @@ impl TyDecl { let call_path = decl.call_path.clone(); let decl: ty::TyDecl = decl_engine.insert(decl).into(); - auto_impl_abi_encode(handler, &mut ctx, decl.clone()); + if ctx.namespace.name.as_ref().unwrap().as_str() == "logging" { + auto_impl_abi_encode(handler, &mut ctx, decl.clone()); + } // insert the struct decl into namespace ctx.insert_symbol(handler, call_path.suffix, decl.clone())?; diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 0b811e164de..e39bee348e5 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -1465,6 +1465,7 @@ impl ty::TyExpression { instantiate_constant_expression(ctx, const_ref, call_path_binding) } (false, None, None, None) => { + dbg!(1); return Err(handler.emit_err(CompileError::SymbolNotFound { name: unknown_call_path_binding.inner.call_path.suffix.clone(), span: unknown_call_path_binding.inner.call_path.suffix.span(), diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index 28db7d698e9..00c37ae204c 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -33,21 +33,27 @@ impl ty::TyAstNode { let node = ty::TyAstNode { content: match node.content.clone() { AstNodeContent::UseStatement(a) => { + // dbg!(&a); let mut is_external = false; + // dbg!(is_external, &ctx.namespace.name); if let Some(submodule) = ctx.namespace.submodule(&[a.call_path[0].clone()]) { is_external = submodule.is_external; } + // dbg!(is_external, &ctx.namespace.name); let path = if is_external || a.is_absolute { a.call_path.clone() } else { ctx.namespace.find_module_path(&a.call_path) }; + // dbg!(&path); let _ = match a.import_type { ImportType::Star => { // try a standard starimport first let star_import_handler = Handler::default(); + // dbg!(&ctx.namespace.name); let import = ctx.star_import(&star_import_handler, &path, a.is_absolute); + if import.is_ok() { handler.append(star_import_handler); import diff --git a/sway-core/src/semantic_analysis/namespace/items.rs b/sway-core/src/semantic_analysis/namespace/items.rs index ae4456a17e7..a4229f8facb 100644 --- a/sway-core/src/semantic_analysis/namespace/items.rs +++ b/sway-core/src/semantic_analysis/namespace/items.rs @@ -260,9 +260,12 @@ impl Items { pub(crate) fn check_symbol(&self, name: &Ident) -> Result<&ty::TyDecl, CompileError> { self.symbols .get(name) - .ok_or_else(|| CompileError::SymbolNotFound { - name: name.clone(), - span: name.span(), + .ok_or_else(|| { + // dbg!(1); + CompileError::SymbolNotFound { + name: name.clone(), + span: name.span(), + } }) } diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index 97522308c9e..13f6dd100c9 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -444,6 +444,7 @@ impl Module { }; } None => { + dbg!(1); return Err(handler.emit_err(CompileError::SymbolNotFound { name: item.clone(), span: item.span(), @@ -534,6 +535,7 @@ impl Module { None => add_synonym(variant_name), }; } else { + dbg!(1); return Err(handler.emit_err(CompileError::SymbolNotFound { name: variant_name.clone(), span: variant_name.span(), @@ -547,6 +549,7 @@ impl Module { } } None => { + dbg!(1); return Err(handler.emit_err(CompileError::SymbolNotFound { name: enum_name.clone(), span: enum_name.span(), @@ -623,6 +626,7 @@ impl Module { } } None => { + dbg!(1); return Err(handler.emit_err(CompileError::SymbolNotFound { name: enum_name.clone(), span: enum_name.span(), diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 083c1c04419..a43ff66e43c 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -266,6 +266,7 @@ impl Root { engines.te().get(type_decl.ty.unwrap().type_id) } _ => { + dbg!(1); return Err(handler.emit_err(CompileError::SymbolNotFound { name: symbol.clone(), span: symbol.span(), @@ -345,10 +346,18 @@ impl Root { // TODO: check that the symbol import is public? self.resolve_symbol(handler, engines, src_path, true_symbol, self_type) } - _ => module - .check_symbol(true_symbol) - .map_err(|e| handler.emit_err(e)) - .cloned(), + _ => { + // dbg!( + // mod_path, + // symbol, + // module, + // self_type, + // ); + module + .check_symbol(true_symbol) + .map_err(|e| handler.emit_err(e)) + .cloned() + }, } } } diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index a7662a434b5..339abc78621 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -997,10 +997,13 @@ impl TraitMap { span: symbol.span(), }, )), - Ordering::Less => Err(handler.emit_err(CompileError::SymbolNotFound { - name: symbol.clone(), - span: symbol.span(), - })), + Ordering::Less => { + // dbg!(1); + Err(handler.emit_err(CompileError::SymbolNotFound { + name: symbol.clone(), + span: symbol.span(), + })) + }, Ordering::Equal => Ok(candidates.values().next().unwrap().clone()), } } diff --git a/sway-lib-core/src/codec.sw b/sway-lib-core/src/codec.sw index 7f455edba9f..60abbe526f6 100644 --- a/sway-lib-core/src/codec.sw +++ b/sway-lib-core/src/codec.sw @@ -1,5 +1,7 @@ library; +use ::raw_slice::*; + pub struct Buffer { buffer: raw_ptr, cap: u64, @@ -23,9 +25,7 @@ impl Buffer { let count = __size_of::(); if self.cap >= self.size + count { - asm(dst: self.buffer, val: val, count: count) { - mcp dst val count; - }; + self.buffer.add::(self.size).write(val); self.size += count; } else { __revert(123456789); @@ -34,6 +34,12 @@ impl Buffer { } } +impl AsRawSlice for Buffer { + fn as_raw_slice(self) -> raw_slice { + asm(ptr: (self.buffer, self.size)) { ptr: raw_slice } + } +} + pub trait AbiEncode { fn abi_encode(self, ref mut buffer: Buffer); } diff --git a/test/src/e2e_vm_tests/harness.rs b/test/src/e2e_vm_tests/harness.rs index 1b87b4f1164..adefbc4b19b 100644 --- a/test/src/e2e_vm_tests/harness.rs +++ b/test/src/e2e_vm_tests/harness.rs @@ -177,9 +177,19 @@ pub(crate) fn runs_in_vm( let mut i = Interpreter::with_storage(storage, Default::default(), GasCosts::default()); let transition = i.transact(tx)?; + + for r in transition.receipts() { + match r { + Receipt::LogData { data, .. } => { + eprintln!("LogData: {:?}", data); + }, + _ => { dbg!(r); } + } + } + Ok(VMExecutionResult::Fuel( *transition.state(), - dbg!(transition.receipts().to_vec()), + transition.receipts().to_vec(), )) } BuildTarget::EVM => { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/logging/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/logging/src/main.sw index c8e698be33c..777a2d4be1c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/logging/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/logging/src/main.sw @@ -6,10 +6,12 @@ struct S { a: u64 } -fn main() { +fn main() -> u64 { let s = S{ a: 1 }; let buffer = encode(s); - __log(buffer); + let slice: raw_slice = buffer.as_raw_slice(); + __log(slice); + 0 }