## Coverage Report

#### Created: 2025-09-08 21:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /home/noah/src/ruchy/src/backend/transpiler/types.rs

    Line
    Count
    Source
    1
    //! Type transpilation and struct/trait definitions
    2
    3
    #![allow(clippy::missing_errors_doc)]
    4
    #![allow(clippy::wildcard_imports)]
    5
    #![allow(clippy::collapsible_else_if)]
    6
    #![allow(clippy::only_used_in_recursion)]
    7
    8
    use super::*;
    9
    use crate::frontend::ast::{EnumVariant, ImplMethod, StructField, TraitMethod, Type};
    10
    use anyhow::{bail, Result};
    11
    use proc_macro2::TokenStream;
    12
    use quote::{format_ident, quote};
    13
    14
    impl Transpiler {
    15
        /// Transpiles type annotations
    16
        ///
    17
        /// # Examples
    18
        ///
    19
        /// ```
    20
        /// use ruchy::{Transpiler, Parser};
    21
        ///
    22
        /// // Basic types
    23
        /// let transpiler = Transpiler::new();
    24
        /// let mut parser = Parser::new("let x: i32 = 42");
    25
        /// let ast = parser.parse().unwrap();
    26
        ///
    27
        /// let result = transpiler.transpile(&ast).unwrap();
    28
        /// let code = result.to_string();
    29
        /// assert!(code.contains("i32"));
    30
        /// assert!(code.contains("42"));
    31
        /// ```
    32
        ///
    33
        /// ```
    34
        /// use ruchy::{Transpiler, Parser};
    35
        ///
    36
        /// // Generic types
    37
        /// let transpiler = Transpiler::new();
    38
        /// let mut parser = Parser::new("let v: Vec<i32> = vec![1, 2, 3]");
    39
        /// let ast = parser.parse().unwrap();
    40
        ///
    41
        /// let result = transpiler.transpile(&ast).unwrap();
    42
        /// let code = result.to_string();
    43
        /// assert!(code.contains("Vec"));
    44
        /// assert!(code.contains("i32"));
    45
        /// ```
    46
        ///
    47
        /// ```
    48
        /// use ruchy::{Transpiler, Parser};
    49
        ///
    50
        /// // Optional types
    51
        /// let transpiler = Transpiler::new();
    52
        /// let mut parser = Parser::new("let opt: Option<i32> = Some(42)");
    53
        /// let ast = parser.parse().unwrap();
    54
        ///
    55
        /// let result = transpiler.transpile(&ast).unwrap();
    56
        /// let code = result.to_string();
    57
        /// assert!(code.contains("Option"));
    58
        /// assert!(code.contains("Some"));
    59
        /// ```
    60
    0
        pub fn transpile_type(&self, ty: &Type) -> Result<TokenStream> {
    61
            use crate::frontend::ast::TypeKind;
    62
    63
    0
            match &ty.kind {
    64
    0
                TypeKind::Named(name) => {
    65
                    // Map common Ruchy types to Rust types
    66
    0
                    let rust_type = match name.as_str() {
    67
    0
                        "int" => quote! { i64 },
    68
    0
                        "float" => quote! { f64 },
    69
    0
                        "bool" => quote! { bool },
    70
    0
                        "str" => quote! { str },  // Plain str type (will be used with & for references)
    71
    0
                        "string" | "String" => quote! { String },
    72
    0
                        "char" => quote! { char },
    73
                        // PERFORMANCE OPTIMIZATION: Use Rust type inference instead of Any
    74
    0
                        "_" | "Any" => quote! { _ },
    75
                        _ => {
    76
    0
                            let type_ident = format_ident!("{}", name);
    77
    0
                            quote! { #type_ident }
    78
                        }
    79
                    };
    80
    0
                    Ok(rust_type)
    81
                }
    82
    0
                TypeKind::Generic { base, params } => {
    83
    0
                    let base_ident = format_ident!("{}", base);
    84
    0
                    let param_tokens: Result<Vec<_>> =
    85
    0
                        params.iter().map(|p| self.transpile_type(p)).collect();
    86
    0
                    let param_tokens = param_tokens?;
    87
    0
                    Ok(quote! { #base_ident<#(#param_tokens),*> })
    88
                }
    89
    0
                TypeKind::Optional(inner) => {
    90
    0
                    let inner_tokens = self.transpile_type(inner)?;
    91
    0
                    Ok(quote! { Option<#inner_tokens> })
    92
                }
    93
    0
                TypeKind::List(elem_type) => {
    94
    0
                    let elem_tokens = self.transpile_type(elem_type)?;
    95
    0
                    Ok(quote! { Vec<#elem_tokens> })
    96
                }
    97
    0
                TypeKind::Tuple(types) => {
    98
    0
                    let type_tokens: Result<Vec<_>> =
    99
    0
                        types.iter().map(|t| self.transpile_type(t)).collect();
    100
    0
                    let type_tokens = type_tokens?;
    101
    0
                    Ok(quote! { (#(#type_tokens),*) })
    102
                }
    103
    0
                TypeKind::Function { params, ret } => {
    104
    0
                    let param_tokens: Result<Vec<_>> =
    105
    0
                        params.iter().map(|p| self.transpile_type(p)).collect();
    106
    0
                    let param_tokens = param_tokens?;
    107
    0
                    let ret_tokens = self.transpile_type(ret)?;
    108
    109
                    // Rust function type syntax
    110
    0
                    Ok(quote! { fn(#(#param_tokens),*) -> #ret_tokens })
    111
                }
    112
                TypeKind::DataFrame { .. } => {
    113
                    // DataFrames map to Polars DataFrame type
    114
    0
                    Ok(quote! { polars::prelude::DataFrame })
    115
                }
    116
                TypeKind::Series { .. } => {
    117
                    // Series maps to Polars Series type
    118
    0
                    Ok(quote! { polars::prelude::Series })
    119
                }
    120
    0
                TypeKind::Reference { is_mut, inner } => {
    121
                    // Special case: &str should not become &&str
    122
    0
                    if let TypeKind::Named(name) = &inner.kind {
    123
    0
                        if name == "str" {
    124
                            // str is already a reference type in Rust
    125
    0
                            return if *is_mut {
    126
    0
                                Ok(quote! { &mut str })
    127
                            } else {
    128
    0
                                Ok(quote! { &str })
    129
                            };
    130
    0
                        }
    131
    0
                    }
    132
    133
    0
                    let inner_tokens = self.transpile_type(inner)?;
    134
    0
                    if *is_mut {
    135
    0
                        Ok(quote! { &mut #inner_tokens })
    136
                    } else {
    137
    0
                        Ok(quote! { &#inner_tokens })
    138
                    }
    139
                }
    140
            }
    141
    0
        }
    142
    143
        /// Transpiles struct definitions
    144
    0
        pub fn transpile_struct(
    145
    0
            &self,
    146
    0
            name: &str,
    147
    0
            type_params: &[String],
    148
    0
            fields: &[StructField],
    149
    0
            is_pub: bool,
    150
    0
        ) -> Result<TokenStream> {
    151
    0
            let struct_name = format_ident!("{}", name);
    152
    153
    0
            let type_param_tokens: Vec<_> =
    154
    0
                type_params.iter().map(|p| format_ident!("{}", p)).collect();
    155
    156
    0
            let field_tokens: Vec<TokenStream> = fields
    157
    0
                .iter()
    158
    0
                .map(|field| {
    159
    0
                    let field_name = format_ident!("{}", field.name);
    160
    0
                    let field_type = self
    161
    0
                        .transpile_type(&field.ty)
    162
    0
                        .unwrap_or_else(|_| quote! { _ });
    163
    164
    0
                    if field.is_pub {
    165
    0
                        quote! { pub #field_name: #field_type }
    166
                    } else {
    167
    0
                        quote! { #field_name: #field_type }
    168
                    }
    169
    0
                })
    170
    0
                .collect();
    171
    172
    0
            let visibility = if is_pub { quote! { pub } } else { quote! {} };
    173
    174
    0
            if type_params.is_empty() {
    175
    0
                Ok(quote! {
    176
                    #visibility struct #struct_name {
    177
                        #(#field_tokens,)*
    178
                    }
    179
                })
    180
            } else {
    181
    0
                Ok(quote! {
    182
                    #visibility struct #struct_name<#(#type_param_tokens),*> {
    183
                        #(#field_tokens,)*
    184
                    }
    185
                })
    186
            }
    187
    0
        }
    188
    189
        /// Transpiles trait definitions
    190
    0
        pub fn transpile_enum(
    191
    0
            &self,
    192
    0
            name: &str,
    193
    0
            type_params: &[String],
    194
    0
            variants: &[EnumVariant],
    195
    0
            is_pub: bool,
    196
    0
        ) -> Result<TokenStream> {
    197
    0
            let enum_name = format_ident!("{}", name);
    198
    199
    0
            let type_param_tokens: Vec<_> =
    200
    0
                type_params.iter().map(|p| format_ident!("{}", p)).collect();
    201
    202
            // Check if any variant has discriminant values
    203
    0
            let has_discriminants = variants.iter().any(|v| v.discriminant.is_some());
    204
    205
    0
            let variant_tokens: Vec<TokenStream> = variants
    206
    0
                .iter()
    207
    0
                .map(|variant| {
    208
    0
                    let variant_name = format_ident!("{}", variant.name);
    209
    210
    0
                    if let Some(fields) = &variant.fields {
    211
                        // Tuple variant (can't have discriminant)
    212
    0
                        let field_types: Vec<TokenStream> = fields
    213
    0
                            .iter()
    214
    0
                            .map(|ty| self.transpile_type(ty).unwrap_or_else(|_| quote! { _ }))
    215
    0
                            .collect();
    216
    0
                        quote! { #variant_name(#(#field_types),*) }
    217
    0
                    } else if let Some(disc_value) = variant.discriminant {
    218
                        // Unit variant with explicit discriminant
    219
                        // Convert to i32 literal without suffix for cleaner output
    220
    0
                        let disc_literal = proc_macro2::Literal::i32_unsuffixed(disc_value as i32);
    221
    0
                        quote! { #variant_name = #disc_literal }
    222
                    } else {
    223
                        // Unit variant without discriminant
    224
    0
                        quote! { #variant_name }
    225
                    }
    226
    0
                })
    227
    0
                .collect();
    228
    229
    0
            let visibility = if is_pub { quote! { pub } } else { quote! {} };
    230
    231
            // Add #[repr(i32)] attribute if enum has discriminant values
    232
    0
            let repr_attr = if has_discriminants {
    233
    0
                quote! { #[repr(i32)] }
    234
            } else {
    235
    0
                quote! {}
    236
            };
    237
    238
    0
            if type_params.is_empty() {
    239
    0
                Ok(quote! {
    240
                    #repr_attr
    241
                    #visibility enum #enum_name {
    242
                        #(#variant_tokens,)*
    243
                    }
    244
                })
    245
            } else {
    246
    0
                Ok(quote! {
    247
                    #repr_attr
    248
                    #visibility enum #enum_name<#(#type_param_tokens),*> {
    249
                        #(#variant_tokens,)*
    250
                    }
    251
                })
    252
            }
    253
    0
        }
    254
    255
    0
        pub fn transpile_trait(
    256
    0
            &self,
    257
    0
            name: &str,
    258
    0
            type_params: &[String],
    259
    0
            methods: &[TraitMethod],
    260
    0
            is_pub: bool,
    261
    0
        ) -> Result<TokenStream> {
    262
    0
            let trait_name = format_ident!("{}", name);
    263
    264
    0
            let method_tokens: Result<Vec<_>> = methods
    265
    0
                .iter()
    266
    0
                .map(|method| {
    267
    0
                    let method_name = format_ident!("{}", method.name);
    268
    269
                    // Process parameters
    270
    0
                    let param_tokens: Vec<TokenStream> = method
    271
    0
                        .params
    272
    0
                        .iter()
    273
    0
                        .enumerate()
    274
    0
                        .map(|(i, param)| {
    275
    0
                            if i == 0 && (param.name() == "self" || param.name() == "&self") {
    276
                                // Handle self parameter - check if it's &self or self
    277
    0
                                if param.name().starts_with('&') {
    278
    0
                                    quote! { &self }
    279
                                } else {
    280
    0
                                    quote! { self }
    281
                                }
    282
                            } else {
    283
    0
                                let param_name = format_ident!("{}", param.name());
    284
    0
                                let type_tokens = self
    285
    0
                                    .transpile_type(&param.ty)
    286
    0
                                    .unwrap_or_else(|_| quote! { _ });
    287
    0
                                quote! { #param_name: #type_tokens }
    288
                            }
    289
    0
                        })
    290
    0
                        .collect();
    291
    292
                    // Process return type
    293
    0
                    let return_type_tokens = if let Some(ref ty) = method.return_type {
    294
    0
                        let ty_tokens = self.transpile_type(ty)?;
    295
    0
                        quote! { -> #ty_tokens }
    296
                    } else {
    297
    0
                        quote! {}
    298
                    };
    299
    300
                    // Process method visibility
    301
    0
                    let visibility = if method.is_pub { quote! { pub } } else { quote! {} };
    302
    303
                    // Process method body (if default implementation)
    304
    0
                    if let Some(ref body) = method.body {
    305
    0
                        let body_tokens = self.transpile_expr(body)?;
    306
    0
                        Ok(quote! {
    307
                            #visibility fn #method_name(#(#param_tokens),*) #return_type_tokens {
    308
                                #body_tokens
    309
                            }
    310
                        })
    311
                    } else {
    312
    0
                        Ok(quote! {
    313
                            #visibility fn #method_name(#(#param_tokens),*) #return_type_tokens;
    314
                        })
    315
                    }
    316
    0
                })
    317
    0
                .collect();
    318
    319
    0
            let method_tokens = method_tokens?;
    320
    321
    0
            let type_param_tokens: Vec<_> =
    322
    0
                type_params.iter().map(|p| format_ident!("{}", p)).collect();
    323
    324
    0
            let visibility = if is_pub { quote! { pub } } else { quote! {} };
    325
    326
    0
            if type_params.is_empty() {
    327
    0
                Ok(quote! {
    328
                    #visibility trait #trait_name {
    329
                        #(#method_tokens)*
    330
                    }
    331
                })
    332
            } else {
    333
    0
                Ok(quote! {
    334
                    #visibility trait #trait_name<#(#type_param_tokens),*> {
    335
                        #(#method_tokens)*
    336
                    }
    337
                })
    338
            }
    339
    0
        }
    340
    341
        /// Transpiles impl blocks
    342
    0
        pub fn transpile_impl(
    343
    0
            &self,
    344
    0
            for_type: &str,
    345
    0
            type_params: &[String],
    346
    0
            trait_name: Option<&str>,
    347
    0
            methods: &[ImplMethod],
    348
    0
            _is_pub: bool,
    349
    0
        ) -> Result<TokenStream> {
    350
    0
            let type_ident = format_ident!("{}", for_type);
    351
    352
    0
            let method_tokens: Result<Vec<_>> = methods
    353
    0
                .iter()
    354
    0
                .map(|method| {
    355
    0
                    let method_name = format_ident!("{}", method.name);
    356
    357
                    // Process parameters
    358
    0
                    let param_tokens: Vec<TokenStream> = method
    359
    0
                        .params
    360
    0
                        .iter()
    361
    0
                        .enumerate()
    362
    0
                        .map(|(i, param)| {
    363
    0
                            if i == 0 && (param.name() == "self" || param.name() == "&self") {
    364
                                // Handle self parameter
    365
    0
                                if param.name().starts_with('&') {
    366
    0
                                    quote! { &self }
    367
                                } else {
    368
    0
                                    quote! { self }
    369
                                }
    370
                            } else {
    371
    0
                                let param_name = format_ident!("{}", param.name());
    372
    0
                                let type_tokens = self
    373
    0
                                    .transpile_type(&param.ty)
    374
    0
                                    .unwrap_or_else(|_| quote! { _ });
    375
    0
                                quote! { #param_name: #type_tokens }
    376
                            }
    377
    0
                        })
    378
    0
                        .collect();
    379
    380
                    // Process return type
    381
    0
                    let return_type_tokens = if let Some(ref ty) = method.return_type {
    382
    0
                        let ty_tokens = self.transpile_type(ty)?;
    383
    0
                        quote! { -> #ty_tokens }
    384
                    } else {
    385
    0
                        quote! {}
    386
                    };
    387
    388
                    // Process method body (always present in ImplMethod)
    389
    0
                    let body_tokens = self.transpile_expr(&method.body)?;
    390
    391
                    // Process method visibility
    392
    0
                    let visibility = if method.is_pub { quote! { pub } } else { quote! {} };
    393
    394
    0
                    Ok(quote! {
    395
                        #visibility fn #method_name(#(#param_tokens),*) #return_type_tokens {
    396
                            #body_tokens
    397
                        }
    398
                    })
    399
    0
                })
    400
    0
                .collect();
    401
    402
    0
            let method_tokens = method_tokens?;
    403
    404
    0
            let type_param_tokens: Vec<_> =
    405
    0
                type_params.iter().map(|p| format_ident!("{}", p)).collect();
    406
    407
    0
            if let Some(trait_name) = trait_name {
    408
    0
                let trait_ident = format_ident!("{}", trait_name);
    409
    0
                if type_params.is_empty() {
    410
    0
                    Ok(quote! {
    411
                        impl #trait_ident for #type_ident {
    412
                            #(#method_tokens)*
    413
                        }
    414
                    })
    415
                } else {
    416
    0
                    Ok(quote! {
    417
                        impl<#(#type_param_tokens),*> #trait_ident for #type_ident<#(#type_param_tokens),*> {
    418
                            #(#method_tokens)*
    419
                        }
    420
                    })
    421
                }
    422
            } else {
    423
    0
                if type_params.is_empty() {
    424
    0
                    Ok(quote! {
    425
                        impl #type_ident {
    426
                            #(#method_tokens)*
    427
                        }
    428
                    })
    429
                } else {
    430
    0
                    Ok(quote! {
    431
                        impl<#(#type_param_tokens),*> #type_ident<#(#type_param_tokens),*> {
    432
                            #(#method_tokens)*
    433
                        }
    434
                    })
    435
                }
    436
            }
    437
    0
        }
    438
    439
        /// Transpiles property test attributes
    440
    0
        pub fn transpile_property_test(&self, expr: &Expr, _attr: &Attribute) -> Result<TokenStream> {
    441
            // Property tests in Rust typically use proptest or quickcheck
    442
            // We'll generate proptest-compatible code
    443
    444
            if let ExprKind::Function {
    445
    0
                name, params, body, ..
    446
    0
            } = &expr.kind
    447
            {
    448
    0
                let fn_name = format_ident!("{}", name);
    449
    450
                // Generate property test parameters
    451
    0
                let param_tokens: Vec<TokenStream> = params
    452
    0
                    .iter()
    453
    0
                    .map(|p| {
    454
    0
                        let param_name = format_ident!("{}", p.name());
    455
    0
                        let type_tokens = self
    456
    0
                            .transpile_type(&p.ty)
    457
    0
                            .unwrap_or_else(|_| quote! { i32 });
    458
    0
                        quote! { #param_name: #type_tokens }
    459
    0
                    })
    460
    0
                    .collect();
    461
    462
    0
                let body_tokens = self.transpile_expr(body)?;
    463
    464
                // Generate the proptest macro invocation
    465
    0
                Ok(quote! {
    466
                    #[cfg(test)]
    467
                    mod #fn_name {
    468
                        use super::*;
    469
                        use proptest::prelude::*;
    470
    471
                        proptest! {
    472
                            #[test]
    473
                            fn #fn_name(#(#param_tokens),*) {
    474
                                #body_tokens
    475
                            }
    476
                        }
    477
                    }
    478
                })
    479
            } else {
    480
    0
                bail!("Property test attribute can only be applied to functions");
    481
            }
    482
    0
        }
    483
    484
        /// Transpiles extension methods into trait + impl
    485
        ///
    486
        /// Generates both a trait definition and an implementation according to the specification:
    487
        /// ```text
    488
        /// Ruchy: extend String { fun is_palindrome(&self) -> bool { ... } }
    489
        /// Rust:  trait StringExt { fn is_palindrome(&self) -> bool; }
    490
        ///        impl StringExt for String { fn is_palindrome(&self) -> bool { ... } }
    491
        /// ```
    492
    0
        pub fn transpile_extend(
    493
    0
            &self,
    494
    0
            target_type: &str,
    495
    0
            methods: &[ImplMethod],
    496
    0
        ) -> Result<TokenStream> {
    497
    0
            let target_ident = format_ident!("{}", target_type);
    498
    0
            let trait_name = format_ident!("{}Ext", target_type); // e.g., StringExt
    499
    500
            // Generate trait definition
    501
    0
            let trait_method_tokens: Result<Vec<_>> = methods
    502
    0
                .iter()
    503
    0
                .map(|method| {
    504
    0
                    let method_name = format_ident!("{}", method.name);
    505
    506
                    // Process parameters
    507
    0
                    let param_tokens: Vec<TokenStream> = method
    508
    0
                        .params
    509
    0
                        .iter()
    510
    0
                        .enumerate()
    511
    0
                        .map(|(i, param)| {
    512
    0
                            if i == 0 && (param.name() == "self" || param.name() == "&self") {
    513
                                // Handle self parameter
    514
    0
                                if param.name().starts_with('&') {
    515
    0
                                    quote! { &self }
    516
                                } else {
    517
    0
                                    quote! { self }
    518
                                }
    519
                            } else {
    520
    0
                                let param_name = format_ident!("{}", param.name());
    521
    0
                                let type_tokens = self
    522
    0
                                    .transpile_type(&param.ty)
    523
    0
                                    .unwrap_or_else(|_| quote! { _ });
    524
    0
                                quote! { #param_name: #type_tokens }
    525
                            }
    526
    0
                        })
    527
    0
                        .collect();
    528
    529
                    // Process return type
    530
    0
                    let return_type_tokens = if let Some(ref ty) = method.return_type {
    531
    0
                        let ty_tokens = self.transpile_type(ty)?;
    532
    0
                        quote! { -> #ty_tokens }
    533
                    } else {
    534
    0
                        quote! {}
    535
                    };
    536
    537
                    // Trait methods are just signatures (no body)
    538
    0
                    Ok(quote! {
    539
                        fn #method_name(#(#param_tokens),*) #return_type_tokens;
    540
                    })
    541
    0
                })
    542
    0
                .collect();
    543
    544
    0
            let trait_method_tokens = trait_method_tokens?;
    545
    546
            // Generate impl definition
    547
    0
            let impl_method_tokens: Result<Vec<_>> = methods
    548
    0
                .iter()
    549
    0
                .map(|method| {
    550
    0
                    let method_name = format_ident!("{}", method.name);
    551
    552
                    // Process parameters (same as trait)
    553
    0
                    let param_tokens: Vec<TokenStream> = method
    554
    0
                        .params
    555
    0
                        .iter()
    556
    0
                        .enumerate()
    557
    0
                        .map(|(i, param)| {
    558
    0
                            if i == 0 && (param.name() == "self" || param.name() == "&self") {
    559
    0
                                if param.name().starts_with('&') {
    560
    0
                                    quote! { &self }
    561
                                } else {
    562
    0
                                    quote! { self }
    563
                                }
    564
                            } else {
    565
    0
                                let param_name = format_ident!("{}", param.name());
    566
    0
                                let type_tokens = self
    567
    0
                                    .transpile_type(&param.ty)
    568
    0
                                    .unwrap_or_else(|_| quote! { _ });
    569
    0
                                quote! { #param_name: #type_tokens }
    570
                            }
    571
    0
                        })
    572
    0
                        .collect();
    573
    574
                    // Process return type
    575
    0
                    let return_type_tokens = if let Some(ref ty) = method.return_type {
    576
    0
                        let ty_tokens = self.transpile_type(ty)?;
    577
    0
                        quote! { -> #ty_tokens }
    578
                    } else {
    579
    0
                        quote! {}
    580
                    };
    581
    582
                    // Impl methods have bodies
    583
    0
                    let body_tokens = self.transpile_expr(&method.body)?;
    584
    585
    0
                    Ok(quote! {
    586
                        fn #method_name(#(#param_tokens),*) #return_type_tokens {
    587
                            #body_tokens
    588
                        }
    589
                    })
    590
    0
                })
    591
    0
                .collect();
    592
    593
    0
            let impl_method_tokens = impl_method_tokens?;
    594
    595
            // Generate both trait and impl
    596
    0
            Ok(quote! {
    597
                trait #trait_name {
    598
                    #(#trait_method_tokens)*
    599
                }
    600
    601
                impl #trait_name for #target_ident {
    602
                    #(#impl_method_tokens)*
    603
                }
    604
            })
    605
    0
        }
    606
    }
    607
    608
    #[cfg(test)]
    609
    mod tests {
    610
        use super::*;
    611
    612
        #[test]
    613
        fn test_transpile_result_helpers() {
    614
            let helpers = Transpiler::generate_result_helpers();
    615
            let code = helpers.to_string();
    616
    617
            // Check that the ResultExt trait is generated
    618
            assert!(code.contains("trait ResultExt"));
    619
            assert!(code.contains("map_err_with"));
    620
            assert!(code.contains("unwrap_or_else_with"));
    621
            assert!(code.contains("and_then_with"));
    622
            assert!(code.contains("or_else_with"));
    623
        }
    624
    }