@@ -97,22 +97,43 @@ pub fn generate_data_types<'ink>(
97
97
}
98
98
}
99
99
100
- // now create all other types (enum's, arrays, etc.)
100
+ // Separate function types from other types to process them later
101
+ let mut function_types = vec ! [ ] ;
102
+ let mut non_function_types = vec ! [ ] ;
103
+
101
104
for ( name, user_type) in & types {
105
+ if let DataTypeInformation :: Struct { source : StructSource :: Pou ( PouType :: Function | PouType :: Method { .. } , ..) , .. } = user_type. get_type_information ( ) {
106
+ function_types. push ( ( * name, * user_type) ) ;
107
+ } else {
108
+ non_function_types. push ( ( * name, * user_type) ) ;
109
+ }
110
+ }
111
+
112
+ // First create all POU types (excluding functions/methods) - this includes function blocks like ClassA, ClassB
113
+ for ( name, user_type) in & pou_types {
114
+ let gen_type = generator. create_type ( name, user_type) ?;
115
+ generator. types_index . associate_pou_type ( name, gen_type) ?
116
+ }
117
+
118
+ // Then create function types now that all POU types are available
119
+ for ( name, user_type) in & function_types {
102
120
let gen_type = generator. create_type ( name, user_type) ?;
103
121
generator. types_index . associate_type ( name, gen_type) ?
104
122
//Get and associate debug type
105
123
}
106
124
107
- for ( name, user_type) in & pou_types {
125
+ // Finally create all non-function types (enum's, arrays, VTable structs, etc.)
126
+ for ( name, user_type) in & non_function_types {
108
127
let gen_type = generator. create_type ( name, user_type) ?;
109
- generator. types_index . associate_pou_type ( name, gen_type) ?
128
+ generator. types_index . associate_type ( name, gen_type) ?
129
+ //Get and associate debug type
110
130
}
111
131
112
- // Combine the types and pou_types into a single Vector
132
+ // Combine all types in the order they were processed
113
133
let mut types_to_init = VecDeque :: new ( ) ;
114
- types_to_init. extend ( types) ;
115
134
types_to_init. extend ( pou_types) ;
135
+ types_to_init. extend ( function_types) ;
136
+ types_to_init. extend ( non_function_types) ;
116
137
// now since all types should be available in the llvm index, we can think about constructing and associating
117
138
for ( _, user_type) in & types_to_init {
118
139
//Expand all types
@@ -176,7 +197,7 @@ pub fn generate_data_types<'ink>(
176
197
}
177
198
178
199
impl < ' ink > DataTypeGenerator < ' ink , ' _ > {
179
- fn create_function_type ( & self , name : & str ) -> Result < FunctionType < ' ink > , Diagnostic > {
200
+ fn create_function_type ( & mut self , name : & str ) -> Result < FunctionType < ' ink > , Diagnostic > {
180
201
let return_type_dt = self . index . find_return_type ( name) . unwrap_or ( self . index . get_void_type ( ) ) ;
181
202
182
203
let return_type = self
@@ -190,8 +211,20 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
190
211
// For methods, we need to add the 'this' parameter as the first parameter
191
212
if let Some ( PouIndexEntry :: Method { parent_name, .. } ) = self . index . find_pou ( name) {
192
213
// Get the owner class type and add it as the first parameter (this pointer)
193
- if let Ok ( owner_type) = self . types_index . get_associated_type ( parent_name) {
214
+ // If the parent type is not available yet (e.g., during early type creation),
215
+ // we'll create a properly named opaque struct as placeholder
216
+ if let Ok ( owner_type) = self . types_index . get_associated_pou_type ( parent_name) {
194
217
parameter_types. push ( owner_type. ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_GENERIC ) ) . into ( ) ) ;
218
+ } else {
219
+ // Create an opaque struct type with the exact same name that will be used
220
+ // when the full type is created. This ensures LLVM will treat them as the same type.
221
+ let opaque_struct = self . llvm . context . opaque_struct_type ( parent_name) ;
222
+ let opaque_type: BasicTypeEnum = opaque_struct. into ( ) ;
223
+
224
+ // Register it in the POU type index for this generation session
225
+ let _ = self . types_index . associate_pou_type ( parent_name, opaque_type. as_any_type_enum ( ) ) ;
226
+
227
+ parameter_types. push ( opaque_type. ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_GENERIC ) ) . into ( ) ) ;
195
228
}
196
229
}
197
230
@@ -206,10 +239,11 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
206
239
207
240
parameter_types. extend ( declared_params) ;
208
241
209
- let fn_type = match dbg ! ( return_type) {
242
+ let fn_type = match return_type {
210
243
AnyTypeEnum :: IntType ( value) => value. fn_type ( parameter_types. as_slice ( ) , false ) ,
211
244
AnyTypeEnum :: VoidType ( value) => value. fn_type ( parameter_types. as_slice ( ) , false ) ,
212
- _ => unimplemented ! ( ) ,
245
+ AnyTypeEnum :: FloatType ( value) => value. fn_type ( parameter_types. as_slice ( ) , false ) ,
246
+ _ => unimplemented ! ( "Unsupported function return type: {:?}" , return_type) ,
213
247
} ;
214
248
215
249
Ok ( fn_type)
@@ -248,9 +282,11 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
248
282
StructSource :: Pou ( PouType :: Function | PouType :: Method { .. } , ..) => {
249
283
let gen_type = self . create_function_type ( name) ?;
250
284
251
- // TODO(vosa): Strictly speaking we don't need to register in LLVM index, i.e. `return Ok(gen_type.as_any_type_enum())` would suffice without breaking any tests; re-think approach with AnyType changes in API
285
+ // Associate the function type in the POU index
252
286
self . types_index . associate_pou_type ( name, gen_type. as_any_type_enum ( ) ) ?;
253
- self . types_index . get_associated_function_type ( name) . map ( |it| it. as_any_type_enum ( ) )
287
+
288
+ // Return the function type
289
+ Ok ( gen_type. as_any_type_enum ( ) )
254
290
}
255
291
StructSource :: Pou ( ..) => self
256
292
. types_index
0 commit comments