@@ -1186,6 +1186,8 @@ pub fn (mut g Gen) gen() string {
11861186 // 3.6. Builtin helpers (array__free, etc.)
11871187 // IError__free - C interop in source doesn't generate correctly
11881188 g.sb.writeln ('static inline void IError__free(IError* ie) { if (ie && ie->_object) free(ie->_object); }' )
1189+ // IError_str - convert IError to string by calling msg() method
1190+ g.sb.writeln ('static inline string IError_str(IError e) { return e.msg ? e.msg(e._object) : (string){"", 0}; }' )
11891191 // array__free - inline implementation since method may not be generated due to $if blocks
11901192 g.sb.writeln ('static inline void array__free(array* a) { if (a->data) free(a->data); a->data = 0; a->len = 0; a->cap = 0; }' )
11911193 // Array_string__free - free each string then free the array
@@ -1948,6 +1950,10 @@ fn (mut g Gen) infer_type(node ast.Expr) string {
19481950 if t := g.const_types[node.name] {
19491951 return t
19501952 }
1953+ // Special case: 'err' in or-blocks is always IError
1954+ if node.name == 'err' {
1955+ return 'IError'
1956+ }
19511957 return 'int'
19521958 }
19531959 ast.ParenExpr {
@@ -5971,7 +5977,18 @@ fn (mut g Gen) gen_expr(node ast.Expr) {
59715977 g.gen_expr (arg)
59725978 }
59735979 } else {
5974- g.gen_expr (arg)
5980+ // Check if IError needs to be converted to string
5981+ arg_type := g.infer_type (arg)
5982+ // Convert IError to string for print functions or when param expects string
5983+ is_print_fn := name in ['println' , 'eprintln' , 'print' , 'eprint' ]
5984+ if arg_type == 'IError' && (param_type == 'string' || is_print_fn) {
5985+ // Convert IError to string: IError_str(err)
5986+ g.sb.write_string ('IError_str(' )
5987+ g.gen_expr (arg)
5988+ g.sb.write_string (')' )
5989+ } else {
5990+ g.gen_expr (arg)
5991+ }
59755992 }
59765993 }
59775994 g.cur_match_type = old_match_type_arg
@@ -6763,7 +6780,18 @@ fn (mut g Gen) gen_expr(node ast.Expr) {
67636780 }
67646781 g.gen_expr (node.expr)
67656782 } else {
6766- g.gen_expr (node.expr)
6783+ // Check if IError needs to be converted to string
6784+ arg_type := g.infer_type (node.expr)
6785+ // Convert IError to string for print functions or when param expects string
6786+ is_print_fn := name in ['println' , 'eprintln' , 'print' , 'eprint' ]
6787+ if arg_type == 'IError' && (param_type == 'string' || is_print_fn) {
6788+ // Convert IError to string: IError_str(err)
6789+ g.sb.write_string ('IError_str(' )
6790+ g.gen_expr (node.expr)
6791+ g.sb.write_string (')' )
6792+ } else {
6793+ g.gen_expr (node.expr)
6794+ }
67676795 }
67686796 g.sb.write_string (')' )
67696797 }
@@ -7308,121 +7336,38 @@ fn (mut g Gen) gen_expr(node ast.Expr) {
73087336 }
73097337 }
73107338 ast.OrExpr {
7311- // Or expression: expr or { fallback }
7312- // Following V's pattern for Result/Option types
7339+ // Most OrExpr should be expanded by transformer, but handle fallback
7340+ // for edge cases (e.g., builtin functions not tracked by transformer)
73137341 typ := g.infer_type (node.expr)
73147342
7315- // Check if this is a Result type (_result_T)
73167343 if typ.starts_with ('_result_' ) {
7317- // Get base type from result type name
73187344 base_type := g.result_types[typ] or { 'int' }
7319-
7320- if node.stmts.len > = 1 {
7321- // Generate: ({ _result_T _or = expr; if (_or.is_error) { fallback } *(T*)_or.data; })
7322- g.sb.write_string ('({ ${typ } _or_res = ' )
7323- g.gen_expr (node.expr)
7324- g.sb.write_string ('; if (_or_res.is_error) { ' )
7325-
7326- // Handle fallback statements
7327- if node.stmts.len == 1 {
7328- stmt := node.stmts[0 ]
7329- if stmt is ast.ExprStmt {
7330- fallback_expr := stmt.expr
7331- fallback_typ := g.infer_type (fallback_expr)
7332- if fallback_typ == 'void' || fallback_typ == '' {
7333- // panic/exit - just execute
7334- g.gen_expr (fallback_expr)
7335- g.sb.write_string ('; ' )
7336- } else {
7337- // Value fallback - assign to data
7338- g.sb.write_string ('*(${base_type }*)_or_res.data = ' )
7339- g.gen_expr (fallback_expr)
7340- g.sb.write_string ('; ' )
7341- }
7342- }
7343- } else {
7344- // Multiple statements in or block
7345- for stmt in node.stmts {
7346- if stmt is ast.ExprStmt {
7347- g.gen_expr (stmt.expr)
7348- g.sb.write_string ('; ' )
7349- }
7350- }
7345+ g.sb.write_string ('({ ${typ } _or_res = ' )
7346+ g.gen_expr (node.expr)
7347+ g.sb.write_string ('; if (_or_res.is_error) { ' )
7348+ if node.stmts.len == 1 {
7349+ stmt := node.stmts[0 ]
7350+ if stmt is ast.ExprStmt {
7351+ g.gen_expr (stmt.expr)
7352+ g.sb.write_string ('; ' )
73517353 }
7352- g.sb.write_string ('} *(${base_type }*)_or_res.data; })' )
7353- } else {
7354- // No fallback - just extract value
7355- g.sb.write_string ('(*(${base_type }*)(' )
7356- g.gen_expr (node.expr)
7357- g.sb.write_string (').data)' )
73587354 }
7355+ g.sb.write_string ('} *(${base_type }*)_or_res.data; })' )
73597356 } else if typ.starts_with ('_option_' ) {
7360- // Option type handling (similar to Result but checks state != 0)
73617357 base_type := g.option_types[typ] or { 'int' }
7362-
7363- if node.stmts.len > = 1 {
7364- g.sb.write_string ('({ ${typ } _or_opt = ' )
7365- g.gen_expr (node.expr)
7366- g.sb.write_string ('; if (_or_opt.state != 0) { ' )
7367-
7368- if node.stmts.len == 1 {
7369- stmt := node.stmts[0 ]
7370- if stmt is ast.ExprStmt {
7371- fallback_expr := stmt.expr
7372- fallback_typ := g.infer_type (fallback_expr)
7373- if fallback_typ == 'void' || fallback_typ == '' {
7374- g.gen_expr (fallback_expr)
7375- g.sb.write_string ('; ' )
7376- } else {
7377- g.sb.write_string ('*(${base_type }*)_or_opt.data = ' )
7378- g.gen_expr (fallback_expr)
7379- g.sb.write_string ('; ' )
7380- }
7381- }
7382- } else {
7383- for stmt in node.stmts {
7384- if stmt is ast.ExprStmt {
7385- g.gen_expr (stmt.expr)
7386- g.sb.write_string ('; ' )
7387- }
7388- }
7389- }
7390- g.sb.write_string ('} *(${base_type }*)_or_opt.data; })' )
7391- } else {
7392- g.sb.write_string ('(*(${base_type }*)(' )
7393- g.gen_expr (node.expr)
7394- g.sb.write_string (').data)' )
7395- }
7396- } else if typ == 'void' || typ == '' {
7397- // Void type - just execute the expression
7358+ g.sb.write_string ('({ ${typ } _or_opt = ' )
73987359 g.gen_expr (node.expr)
7399- } else if node.stmts.len == 1 {
7400- stmt := node.stmts[0 ]
7401- if stmt is ast.ExprStmt {
7402- fallback_expr := stmt.expr
7403- fallback_typ := g.infer_type (fallback_expr)
7404-
7405- if typ == 'string' {
7406- // For strings, check if empty (simplified "none" check)
7407- g.sb.write_string ('({ string _or_tmp = ' )
7408- g.gen_expr (node.expr)
7409- g.sb.write_string ('; if (_or_tmp.len == 0) { ' )
7410- if fallback_typ == 'void' || fallback_typ == '' {
7411- g.gen_expr (fallback_expr)
7412- g.sb.write_string ('; ' )
7413- } else {
7414- g.sb.write_string ('_or_tmp = ' )
7415- g.gen_expr (fallback_expr)
7416- g.sb.write_string ('; ' )
7417- }
7418- g.sb.write_string ('} _or_tmp; })' )
7419- } else {
7420- g.gen_expr (node.expr)
7360+ g.sb.write_string ('; if (_or_opt.state != 0) { ' )
7361+ if node.stmts.len == 1 {
7362+ stmt := node.stmts[0 ]
7363+ if stmt is ast.ExprStmt {
7364+ g.gen_expr (stmt.expr)
7365+ g.sb.write_string ('; ' )
74217366 }
7422- } else {
7423- g.gen_expr (node.expr)
74247367 }
7368+ g.sb.write_string ('} *(${base_type }*)_or_opt.data; })' )
74257369 } else {
7370+ // Unknown type - just generate the expression
74267371 g.gen_expr (node.expr)
74277372 }
74287373 }
0 commit comments