@@ -56,8 +56,9 @@ impl<'a> TargetRuntime<'a> for SorobanTarget {
5656 * slot
5757 } ;
5858
59- let ret = call ! (
60- HostFunctions :: GetContractData . name( ) ,
59+ // === Call HasContractData ===
60+ let has_data_val = call ! (
61+ HostFunctions :: HasContractData . name( ) ,
6162 & [
6263 slot. into( ) ,
6364 bin. context. i64_type( ) . const_int( storage_type, false ) . into( ) ,
@@ -68,7 +69,49 @@ impl<'a> TargetRuntime<'a> for SorobanTarget {
6869 . unwrap ( )
6970 . into_int_value ( ) ;
7071
71- ret. into ( )
72+ // === Use helper to check if it's true ===
73+ let condition = is_val_true ( bin, has_data_val) ;
74+
75+ // === Prepare blocks ===
76+ let parent = function;
77+ let then_bb = bin. context . append_basic_block ( parent, "has_data" ) ;
78+ let else_bb = bin. context . append_basic_block ( parent, "no_data" ) ;
79+ let merge_bb = bin. context . append_basic_block ( parent, "merge" ) ;
80+
81+ bin. builder
82+ . build_conditional_branch ( condition, then_bb, else_bb)
83+ . unwrap ( ) ;
84+
85+ // === THEN block: call GetContractData ===
86+ bin. builder . position_at_end ( then_bb) ;
87+ let value_from_contract = call ! (
88+ HostFunctions :: GetContractData . name( ) ,
89+ & [
90+ slot. into( ) ,
91+ bin. context. i64_type( ) . const_int( storage_type, false ) . into( ) ,
92+ ]
93+ )
94+ . try_as_basic_value ( )
95+ . left ( )
96+ . unwrap ( ) ;
97+ bin. builder . build_unconditional_branch ( merge_bb) . unwrap ( ) ;
98+ let then_value = value_from_contract;
99+
100+ // === ELSE block: return default ===
101+ bin. builder . position_at_end ( else_bb) ;
102+ let default_value = type_to_tagged_zero_val ( bin, ty) ;
103+
104+ bin. builder . build_unconditional_branch ( merge_bb) . unwrap ( ) ;
105+
106+ // === MERGE block with phi node ===
107+ bin. builder . position_at_end ( merge_bb) ;
108+ let phi = bin
109+ . builder
110+ . build_phi ( bin. context . i64_type ( ) , "storage_result" )
111+ . unwrap ( ) ;
112+ phi. add_incoming ( & [ ( & then_value, then_bb) , ( & default_value, else_bb) ] ) ;
113+
114+ phi. as_basic_value ( )
72115 }
73116
74117 /// Recursively store a type to storage
@@ -222,7 +265,8 @@ impl<'a> TargetRuntime<'a> for SorobanTarget {
222265 } ;
223266
224267 // push the slot to the vector
225- bin. builder
268+ let res = bin
269+ . builder
226270 . build_call (
227271 bin. module
228272 . get_function ( HostFunctions :: VecPushBack . name ( ) )
@@ -237,20 +281,21 @@ impl<'a> TargetRuntime<'a> for SorobanTarget {
237281 . into_int_value ( ) ;
238282
239283 // push the index to the vector
240- bin. builder
284+ let res = bin
285+ . builder
241286 . build_call (
242287 bin. module
243288 . get_function ( HostFunctions :: VecPushBack . name ( ) )
244289 . unwrap ( ) ,
245- & [ vec_new . as_basic_value_enum ( ) . into ( ) , index. into ( ) ] ,
290+ & [ res . as_basic_value_enum ( ) . into ( ) , index. into ( ) ] ,
246291 "push" ,
247292 )
248293 . unwrap ( )
249294 . try_as_basic_value ( )
250295 . left ( )
251296 . unwrap ( )
252297 . into_int_value ( ) ;
253- vec_new
298+ res
254299 }
255300
256301 fn storage_push (
@@ -728,3 +773,47 @@ fn encode_value<'a>(value: IntValue<'a>, shift: u64, add: u64, bin: &'a Binary)
728773 )
729774 . unwrap ( )
730775}
776+
777+ fn is_val_true < ' ctx > ( bin : & Binary < ' ctx > , val : IntValue < ' ctx > ) -> IntValue < ' ctx > {
778+ let tag_mask = bin. context . i64_type ( ) . const_int ( 0xff , false ) ;
779+ let tag_true = bin. context . i64_type ( ) . const_int ( 1 , false ) ;
780+
781+ let tag = bin
782+ . builder
783+ . build_and ( val, tag_mask, "val_tag" )
784+ . expect ( "build_and failed" ) ;
785+
786+ bin. builder
787+ . build_int_compare ( inkwell:: IntPredicate :: EQ , tag, tag_true, "is_val_true" )
788+ . expect ( "build_int_compare failed" )
789+ }
790+
791+ /// Returns a Val representing a default zero value with the correct Soroban Tag.
792+ pub fn type_to_tagged_zero_val < ' ctx > ( bin : & Binary < ' ctx > , ty : & Type ) -> IntValue < ' ctx > {
793+ let context = & bin. context ;
794+ let i64_type = context. i64_type ( ) ;
795+
796+ // Tag definitions from CAP-0046
797+ let tag = match ty {
798+ Type :: Bool => 0 , // Tag::False
799+ Type :: Uint ( 32 ) => 4 , // Tag::U32Val
800+ Type :: Int ( 32 ) => 5 , // Tag::I32Val
801+ Type :: Uint ( 64 ) => 6 , // Tag::U64Small
802+ Type :: Int ( 64 ) => 7 , // Tag::I64Small
803+ Type :: Uint ( 128 ) => 10 , // Tag::U128Small
804+ Type :: Int ( 128 ) => 11 , // Tag::I128Small
805+ Type :: Uint ( 256 ) => 12 , // Tag::U256Small
806+ Type :: Int ( 256 ) => 13 , // Tag::I256Small
807+ Type :: String => 73 , // Tag::StringObject
808+ Type :: Address ( _) => 77 , // Tag::AddressObject
809+ Type :: Void => 2 , // Tag::Void
810+ _ => {
811+ // Fallback to Void for unsupported types
812+ 2 // Tag::Void
813+ }
814+ } ;
815+
816+ // All zero body + tag in lower 8 bits
817+ let tag_val: u64 = tag;
818+ i64_type. const_int ( tag_val, false )
819+ }
0 commit comments