#Help logging allocation error

1 messages · Page 1 of 1 (latest)

granite folio
#
  ctx: *JSContext,
  in_function_body: bool,
  byte_code: []u8,
  // byte_code: u8
};

fn js_new_function_def(ctx: *JSContext) JSFunctionDef {
    // const byte_code = allocator.alloc(u8, @sizeOf(DynBuf));
    const byte_code = try allocator.alloc(u8, 2); 
    std.debug.print("THE BYTECODE {any}", .{byte_code});
    // std.debug.print("AFTER ALLOC");
      // @compileLog(byte_code);

    var fd = JSFunctionDef{
      .ctx = ctx,
      .in_function_body = false,
      .byte_code = &byte_code
      // .byte_code = 1
    };
    return fd;
}```

is giving me 

./src/main.zig:718:23: error: expected type 'JSFunctionDef', found 'std.mem.Allocator.Error'
const byte_code = try allocator.alloc(u8, 2);
^


I'm trying to change the byte_code type so that I can get an error instead of the expected type and print that, but it's not working so well for me
#

trying things like byte_code: allocError![]u8,

ruby dragon
#

I believe it's because the fn's ret type should be !JSFunctionDef

#

file it under misleading error messages

granite folio
#

lol

#

thank you

#

so do you need a ! in front of the return type of any func that trys?

ruby dragon
#

yes, to indicate that it might return an error

granite folio
#

thanks a bunch!

#

hmm still seeing things

#
 var s = JSParseState{
            .token = JSToken {
              .val = TOKENS.TOK_UNDEF,
              .line_num = 1,
              .ptr = 0,
              .u = .{
                  .str = TokenStr{
                      .str = JSValue{ .u = JSValueUnion{
                          .int32 = 5,
                      }, .tag = 5 },
                      .sep = 1,
                  },
                  // 1
              }
            },
            .ctx = ctx,
            .filename = "foo.js",
            .line_num = 1,
            .prev = 0,
            .buf = input,
            .buf_len = 55,
            .index = 0,
            .cur_func = fd,
        };```
#

./src/main.zig:291:25: error: cannot convert error union to payload type. consider using `try`, `catch`, or `if`. expected type 'JSFunctionDef', found '@typeInfo(@typeInfo(@TypeOf(js_new_function_def)).Fn.return_type.?).ErrorUnion.error_set!JSFunctionDef' .cur_func = fd,

ruby dragon
#

you're missing a try someplace

#

I mean

granite folio
#
const JSFunctionDef = struct {
  ctx: *JSContext,
  in_function_body: bool,
  byte_code: *const []u8,
  // byte_code: u8
};
ruby dragon
#

you get fd from that fn and should unwrap it

granite folio
#

it's weird because there's the function that I had to have the possible error for in the return type

#

i don't get fd from that function

#

is the thing

#

oh no wait i do

ruby dragon
#
var fd = JSFunctionDef{
      .ctx = ctx,
      .in_function_body = false,
      .byte_code = &byte_code
      // .byte_code = 1
    };
    return fd;
granite folio
#

🤦‍♂️

#

so here

#
var fd = js_new_function_def(ctx) catch {
      std.debug.print
    };```
ruby dragon
#

depending on what fd is you could var fd = js_new_function_def(ctx) catch JSFunctionDef{some values here};

#

to give it a value

#

or return there and then

granite folio
#
./src/main.zig:264:45: error: integer value 0 cannot be coerced to type 'JSFunctionDef'
    var fd = js_new_function_def(ctx) catch 0;
                                            ^
#

so I think though

#
fn js_new_function_def(ctx: *JSContext) !JSFunctionDef {
    // const byte_code = allocator.alloc(u8, @sizeOf(DynBuf));
    const byte_code = try allocator.alloc(u8, 2); 
    std.debug.print("THE BYTECODE {any}", .{byte_code});
    // std.debug.print("AFTER ALLOC");
      // @compileLog(byte_code);

    var fd = JSFunctionDef{
      .ctx = ctx,
      .in_function_body = false,
      .byte_code = &byte_code
      // .byte_code = 1
    };
    return fd;
}```
#

there isn't something that it should be if that allocation fails

#

so I think I need to be catching on the allocation failure instead?

ruby dragon
#

you could @panic there

granite folio
#

well I think that it is actually failing right now

#

might be wrong

ruby dragon
#

or var fd = try js_new_function_def(ctx); and propagate the error up

granite folio
#

but ideally I'd be able to log what the outcome of the allocation is

#
./src/main.zig:264:14: error: expected type 'JSValue', found '@typeInfo(@typeInfo(@TypeOf(js_new_function_def)).Fn.return_type.?).ErrorUnion.error_set'
    var fd = try js_new_function_def(ctx);
             ^```
ruby dragon
#

because that fn's ret type's missing an !

#

or handle it there

granite folio
#

yeah I'm trying to catch there but I think I'm doing it wrong

#
./src/main.zig:721:46: error: incompatible types: 'void' and '[]u8'
    const byte_code = allocator.alloc(u8, 2) catch |x| {
                                             ^```
#
 const byte_code = allocator.alloc(u8, 2) catch |x| {
      std.debug.print("THE ERROR {}", .{x});
    };
hybrid oasis
#

a catch statement by itself doesn't return or do anything extra. foo catch bar will evaluate bar and try to assign it in place of foo, when foo contains an error.

#

the block evaluates to a void value, because you don't return anything from it

ruby dragon
#

InK got this :)

hybrid oasis
#

in many situations, you can label the block, and return a value from it, e.g. blk: { print(...); break :blk val; }

#

though, in this case that is probably not very wise, given that you've just failed to allocate, so it's not like you can just magic memory into existence

#

in this case, the most typical thing to do is to just return err; or well, x in this case as you've named it, so it can bubble up

#

this is such a common pattern in fact that try foo() is just sugar for foo() catch |err| return err;

#

this works because control flow expressions like return evaluate to noreturn, which means the compiler expects that no value will come from them, because they will instead redirect control flow in some specific way - which, as you can imagine, return does in fact redirect control flow

ruby dragon
#

slap a ! on every fn's ret type and propagate it all the way to main() ! and beyond, handle as necessary

hybrid oasis
#

ye

#

that's the path of least resistance anyway

#

you may feel awkward putting potential errors everywhere, but do be aware, that is just part of the zen of zig: it is designed for handling failure, instead of pretending it never happens

granite folio
#

I don't think I can feel awkward yet because I still don't understand how to actually achieve what you're describing

#

one sec and I'll try to share

#
fn js_new_function_def(ctx: *JSContext) !JSFunctionDef {
    // const byte_code = allocator.alloc(u8, @sizeOf(DynBuf));
    const byte_code = allocator.alloc(u8, 2) catch |err|{
      return err;
    };
    defer allocator.free(byte_code);
    std.debug.print("THE BYTECODE {any}", .{byte_code});
    // std.debug.print("AFTER ALLOC");
      // @compileLog(byte_code);

    var fd = JSFunctionDef{
      .ctx = ctx,
      .in_function_body = false,
      .byte_code = &byte_code
      // .byte_code = 1
    };
    return fd;
}```
#

are you saying that I can't log the error that alloc is returning in this function body?

hybrid oasis
#

you can indeed do that

granite folio
#

that's what I'm failing to do

hybrid oasis
#

just put it before the return err; statement in the catch block

ruby dragon
#

that defer allocator.free(byte_code);'s gonna bite you

granite folio
#

so i have this code right now... and this output... with no error that I understand

#
fn js_new_function_def(ctx: *JSContext) !JSFunctionDef {
    // const byte_code = allocator.alloc(u8, @sizeOf(DynBuf));
    const byte_code = allocator.alloc(u8, 2) catch |err|{
      std.debug.print("THE ERROR {}", .{err});
      return err;
    };
    // defer allocator.free(byte_code);
    std.debug.print("THE BYTECODE {any}", .{byte_code});
    // std.debug.print("AFTER ALLOC");
      // @compileLog(byte_code);

    var fd = JSFunctionDef{
      .ctx = ctx,
      .in_function_body = false,
      .byte_code = &byte_code
      // .byte_code = 1
    };
    return fd;
}```
hybrid oasis
#

what's the error?

granite folio
#
./src/main.zig:264:14: error: expected type 'JSValue', found '@typeInfo(@typeInfo(@TypeOf(js_new_function_def)).Fn.return_type.?).ErrorUnion.error_set'
    var fd = try js_new_function_def(ctx);
             ^```
ruby dragon
#

that's because the fn that contains this statement lacks a !

granite folio
#

ok so here is the part where I add ! all the way down

hybrid oasis
#

remember, try foo(); = foo() catch |err| return err;.

granite folio
#

so i tried adding ! all the way down

#

and tries along the way as well

#
var s = JSParseState{
            .token = JSToken {
              .val = TOKENS.TOK_UNDEF,
              .line_num = 1,
              .ptr = 0,
              .u = .{
                  .str = TokenStr{
                      .str = JSValue{ .u = JSValueUnion{
                          .int32 = 5,
                      }, .tag = 5 },
                      .sep = 1,
                  },
                  // 1
              }
            },
            .ctx = ctx,
            .filename = "foo.js",
            .line_num = 1,
            .prev = 0,
            .buf = input,
            .buf_len = 55,
            .index = 0,
            .cur_func = fd,
        };```
#
./src/main.zig:291:25: error: cannot convert error union to payload type. consider using `try`, `catch`, or `if`. expected type 'JSFunctionDef', found '@typeInfo(@typeInfo(@TypeOf(js_new_function_def)).Fn.return_type.?).ErrorUnion.error_set!JSFunctionDef'
            .cur_func = fd,
                        ^```
#

so im guessing that JSParseState needs me to mention that cur_func could be an error?

hybrid oasis
#

that probably means you assigned something to fd, without trying that thing

#

if something returns an error union, you have to unwrap it before you can do anything with the payload

#

either with catch or try

granite folio
#

so surprisingly, i never ended up logging an error

hybrid oasis
#

I would recommend against storing error unions

granite folio
#

but i think the issues went away

#

idk it's hard to tell because now there are other compiler errors lol

#

i'll try the same logic on those and see what I get

#

got through it

#

you all were of tremendous help

hybrid oasis
#

np, we've all been there

granite folio
#

seems the trick you taught me isn't working here

#
./src/main.zig:539:41: error: cannot resolve inferred error set '@typeInfo(@typeInfo(@TypeOf(js_parse_statement_or_decl)).Fn.return_type.?).ErrorUnion.error_set': function 'js_parse_statement_or_decl' not fully analyzed yet
      try js_parse_statement_or_decl(s) catch |err| {
                                        ^```
#

seems the issue is recursion

#
  std.debug.print("IN BLOCK", .{});
  _ = next_token(s);
  if (s.token.val != TOKENS.TOK_RCURL) {
    while (true) {
      // std.debug.print("INFINITE LOOP", .{});
      js_parse_statement_or_decl(s) catch |err| {
        std.debug.print("THE ERR {}", .{err});
        return err;
      };
      // if (err) 
      if (s.token.val == TOKENS.TOK_RCURL) {
        break;
      }
    }
  }
}

fn js_parse_statement_or_decl(s: *JSParseState) !void {
  std.debug.print("PARSING STATEMENT OR DECL\n{}\n", .{s.token.val});
  switch(s.token.val) {
    TOKENS.TOK_LCURL => {
      _ = try js_parse_block(s);
    },
    TOKENS.TOK_RETURN => {
      _ = next_token(s);
      // js_parse_expr(s);

      try emit_return(s, true);
    },
    else => {
      s.token.val = TOKENS.TOK_EOF;
    }
  }
  /```
#

wondering if there's some work around

dense pelican
# granite folio ``` ./src/main.zig:539:41: error: cannot resolve inferred error set '@typeInfo(@...

If it cannot resolve the inferred error set, the solution is to specify the error set. The best version of that is:

fn someRecursiveFunction() MyError!void {...}
// or
fn someRecursiveFunction() error{BadOne, BadTwo}!void {...}

As a quick escape hatch, you can have that function belong to the global error set with anyerror:

fn someRecursiveFunction() anyerror!void {...}

But eventually, the ideal is to define the error set, as anyerror is a less helpful hint to the compiler and to users of the API.

iron ferry
#

(An immutable slice: a slice of immutable data.)

granite folio
#

so the github issue i linked... says that it was solved for self hosted in august

#

i have function a calling function b calling function a

#

I plopped the definition of b into a and it was resolved

#

seems the solve fixes error handling for recursive functions, so long as the recursion is encapsulated in a single func def

#

but not when it's broken out into many