mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 22:35:24 +00:00
stage2: astgen catch
This commit is contained in:
parent
bf014d529a
commit
fb28349349
@ -2570,7 +2570,17 @@ pub fn analyzeIsNull(
|
||||
operand: *Inst,
|
||||
invert_logic: bool,
|
||||
) InnerError!*Inst {
|
||||
return self.fail(scope, src, "TODO implement analysis of isnull and isnotnull", .{});
|
||||
if (operand.value()) |opt_val| {
|
||||
const is_null = opt_val.isNull();
|
||||
return self.constBool(scope, src, invert_logic);
|
||||
}
|
||||
const b = try self.requireRuntimeBlock(scope, src);
|
||||
const inst_tag: Inst.Tag = if (invert_logic) .isnonnull else .isnull;
|
||||
return self.addUnOp(b, src, Type.initTag(.bool), inst_tag, operand);
|
||||
}
|
||||
|
||||
pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) InnerError!*Inst {
|
||||
return self.fail(scope, src, "TODO implement analysis of iserr", .{});
|
||||
}
|
||||
|
||||
/// Asserts that lhs and rhs types are both numeric.
|
||||
|
||||
@ -275,9 +275,9 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
|
||||
.ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)),
|
||||
.For => return forExpr(mod, scope, rl, node.castTag(.For).?),
|
||||
.ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?),
|
||||
.Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?),
|
||||
|
||||
.Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
|
||||
.Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}),
|
||||
.Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),
|
||||
.OrElse => return mod.failNode(scope, node, "TODO implement astgen.expr for .OrElse", .{}),
|
||||
.Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),
|
||||
@ -750,6 +750,93 @@ fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*
|
||||
});
|
||||
}
|
||||
|
||||
fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.op_token].start;
|
||||
|
||||
const err_union_ptr = try expr(mod, scope, .ref, node.lhs);
|
||||
// TODO we could avoid an unnecessary copy if .iserr took a pointer
|
||||
const err_union = try addZIRUnOp(mod, scope, src, .deref, err_union_ptr);
|
||||
const cond = try addZIRUnOp(mod, scope, src, .iserr, err_union);
|
||||
|
||||
var block_scope: Scope.GenZIR = .{
|
||||
.parent = scope,
|
||||
.decl = scope.decl().?,
|
||||
.arena = scope.arena(),
|
||||
.instructions = .{},
|
||||
};
|
||||
defer block_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{
|
||||
.condition = cond,
|
||||
.then_body = undefined, // populated below
|
||||
.else_body = undefined, // populated below
|
||||
}, .{});
|
||||
|
||||
const block = try addZIRInstBlock(mod, scope, src, .{
|
||||
.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
|
||||
});
|
||||
|
||||
// Most result location types can be forwarded directly; however
|
||||
// if we need to write to a pointer which has an inferred type,
|
||||
// proper type inference requires peer type resolution on the if's
|
||||
// branches.
|
||||
const branch_rl: ResultLoc = switch (rl) {
|
||||
.discard, .none, .ty, .ptr, .ref => rl,
|
||||
.inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
|
||||
};
|
||||
|
||||
var err_scope: Scope.GenZIR = .{
|
||||
.parent = scope,
|
||||
.decl = block_scope.decl,
|
||||
.arena = block_scope.arena,
|
||||
.instructions = .{},
|
||||
};
|
||||
defer err_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
var err_val_scope: Scope.LocalVal = undefined;
|
||||
const err_sub_scope = blk: {
|
||||
const payload = node.payload orelse
|
||||
break :blk &err_scope.base;
|
||||
|
||||
const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken());
|
||||
if (mem.eql(u8, err_name, "_"))
|
||||
break :blk &err_scope.base;
|
||||
|
||||
const unwrapped_err_ptr = try addZIRUnOp(mod, &err_scope.base, src, .unwrap_err_code, err_union_ptr);
|
||||
err_val_scope = .{
|
||||
.parent = &err_scope.base,
|
||||
.gen_zir = &err_scope,
|
||||
.name = err_name,
|
||||
.inst = try addZIRUnOp(mod, &err_scope.base, src, .deref, unwrapped_err_ptr),
|
||||
};
|
||||
break :blk &err_val_scope.base;
|
||||
};
|
||||
|
||||
_ = try addZIRInst(mod, &err_scope.base, src, zir.Inst.Break, .{
|
||||
.block = block,
|
||||
.operand = try expr(mod, err_sub_scope, branch_rl, node.rhs),
|
||||
}, .{});
|
||||
|
||||
var not_err_scope: Scope.GenZIR = .{
|
||||
.parent = scope,
|
||||
.decl = block_scope.decl,
|
||||
.arena = block_scope.arena,
|
||||
.instructions = .{},
|
||||
};
|
||||
defer not_err_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
const unwrapped_payload = try addZIRUnOp(mod, ¬_err_scope.base, src, .unwrap_err_unsafe, err_union_ptr);
|
||||
_ = try addZIRInst(mod, ¬_err_scope.base, src, zir.Inst.Break, .{
|
||||
.block = block,
|
||||
.operand = unwrapped_payload,
|
||||
}, .{});
|
||||
|
||||
condbr.positionals.then_body = .{ .instructions = try err_scope.arena.dupe(*zir.Inst, err_scope.instructions.items) };
|
||||
condbr.positionals.else_body = .{ .instructions = try not_err_scope.arena.dupe(*zir.Inst, not_err_scope.instructions.items) };
|
||||
return rlWrap(mod, scope, rl, &block.base);
|
||||
}
|
||||
|
||||
/// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating.
|
||||
/// OK in theory it could do it without allocating. This implementation allocates when the @"" form is used.
|
||||
fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool {
|
||||
@ -1317,7 +1404,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)
|
||||
.inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = for_block },
|
||||
};
|
||||
|
||||
var index_scope: Scope.LocalPtr = undefined;
|
||||
var index_scope: Scope.LocalVal = undefined;
|
||||
const then_sub_scope = blk: {
|
||||
const payload = for_node.payload.castTag(.PointerIndexPayload).?;
|
||||
const is_ptr = payload.ptr_token != null;
|
||||
@ -1335,12 +1422,11 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)
|
||||
if (mem.eql(u8, index_name, "_")) {
|
||||
break :blk &then_scope.base;
|
||||
}
|
||||
// TODO ensure this is const
|
||||
index_scope = .{
|
||||
.parent = &then_scope.base,
|
||||
.gen_zir = &then_scope,
|
||||
.name = index_name,
|
||||
.ptr = index_ptr,
|
||||
.inst = index,
|
||||
};
|
||||
break :blk &index_scope.base;
|
||||
};
|
||||
|
||||
@ -253,6 +253,8 @@ pub const Inst = struct {
|
||||
unwrap_err_safe,
|
||||
/// Same as previous, but without safety checks. Used for orelse, if and while
|
||||
unwrap_err_unsafe,
|
||||
/// Gets the error code value of an error union
|
||||
unwrap_err_code,
|
||||
/// Takes a *E!T and raises a compiler error if T != void
|
||||
ensure_err_payload_void,
|
||||
/// Enum literal
|
||||
@ -298,6 +300,7 @@ pub const Inst = struct {
|
||||
.unwrap_optional_unsafe,
|
||||
.unwrap_err_safe,
|
||||
.unwrap_err_unsafe,
|
||||
.unwrap_err_code,
|
||||
.ensure_err_payload_void,
|
||||
.anyframe_type,
|
||||
.bitnot,
|
||||
@ -454,6 +457,7 @@ pub const Inst = struct {
|
||||
.unwrap_optional_unsafe,
|
||||
.unwrap_err_safe,
|
||||
.unwrap_err_unsafe,
|
||||
.unwrap_err_code,
|
||||
.ptr_type,
|
||||
.ensure_err_payload_void,
|
||||
.enum_literal,
|
||||
|
||||
@ -120,6 +120,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
|
||||
.unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),
|
||||
.unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true),
|
||||
.unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false),
|
||||
.unwrap_err_code => return analyzeInstUnwrapErrCode(mod, scope, old_inst.castTag(.unwrap_err_code).?),
|
||||
.ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?),
|
||||
.array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?),
|
||||
.array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?),
|
||||
@ -800,11 +801,12 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp
|
||||
const operand = try resolveInst(mod, scope, unwrap.positionals.operand);
|
||||
assert(operand.ty.zigTypeTag() == .Pointer);
|
||||
|
||||
if (operand.ty.elemType().zigTypeTag() != .Optional) {
|
||||
return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{operand.ty.elemType()});
|
||||
const elem_type = operand.ty.elemType();
|
||||
if (elem_type.zigTypeTag() != .Optional) {
|
||||
return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{elem_type});
|
||||
}
|
||||
|
||||
const child_type = try operand.ty.elemType().optionalChildAlloc(scope.arena());
|
||||
const child_type = try elem_type.optionalChildAlloc(scope.arena());
|
||||
const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, operand.ty.isConstPtr(), .One);
|
||||
|
||||
if (operand.value()) |val| {
|
||||
@ -829,6 +831,10 @@ fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, saf
|
||||
return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{});
|
||||
}
|
||||
|
||||
fn analyzeInstUnwrapErrCode(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErrCode", .{});
|
||||
}
|
||||
|
||||
fn analyzeInstEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstEnsureErrPayloadVoid", .{});
|
||||
}
|
||||
@ -964,7 +970,8 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
|
||||
const entry = if (val.cast(Value.Payload.ErrorSet)) |payload|
|
||||
(payload.fields.getEntry(field_name) orelse
|
||||
return mod.fail(scope, fieldptr.base.src, "no error named '{}' in '{}'", .{ field_name, child_type })).*
|
||||
else try mod.getErrorValue(field_name);
|
||||
else
|
||||
try mod.getErrorValue(field_name);
|
||||
|
||||
const error_payload = try scope.arena().create(Value.Payload.Error);
|
||||
error_payload.* = .{
|
||||
@ -1298,17 +1305,7 @@ fn analyzeInstCmp(
|
||||
{
|
||||
// comparing null with optionals
|
||||
const opt_operand = if (lhs_ty_tag == .Optional) lhs else rhs;
|
||||
if (opt_operand.value()) |opt_val| {
|
||||
const is_null = opt_val.isNull();
|
||||
return mod.constBool(scope, inst.base.src, if (op == .eq) is_null else !is_null);
|
||||
}
|
||||
const b = try mod.requireRuntimeBlock(scope, inst.base.src);
|
||||
const inst_tag: Inst.Tag = switch (op) {
|
||||
.eq => .isnull,
|
||||
.neq => .isnonnull,
|
||||
else => unreachable,
|
||||
};
|
||||
return mod.addUnOp(b, inst.base.src, Type.initTag(.bool), inst_tag, opt_operand);
|
||||
return mod.analyzeIsNull(scope, inst.base.src, opt_operand, op == .neq);
|
||||
} else if (is_equality_cmp and
|
||||
((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))
|
||||
{
|
||||
@ -1356,8 +1353,9 @@ fn analyzeInstIsNonNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, inver
|
||||
return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic);
|
||||
}
|
||||
|
||||
fn analyzeInstIsErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement analyzeInstIsErr", .{});
|
||||
fn analyzeInstIsErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
const operand = try resolveInst(mod, scope, inst.positionals.operand);
|
||||
return mod.analyzeIsErr(scope, inst.base.src, operand);
|
||||
}
|
||||
|
||||
fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user