mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
AstGen: basic defer implementation
This commit is contained in:
parent
b4aec0e31d
commit
a59bcae59f
13
BRANCH_TODO
13
BRANCH_TODO
@ -1,3 +1,7 @@
|
||||
* defer
|
||||
- `break`
|
||||
- `continue`
|
||||
* nested function decl: how to refer to params?
|
||||
* look for cached zir code
|
||||
* save zir code to cache
|
||||
* keep track of file dependencies/dependants
|
||||
@ -13,6 +17,15 @@
|
||||
on each usingnamespace decl
|
||||
* handle usingnamespace cycles
|
||||
|
||||
* compile error for return inside defer expression
|
||||
|
||||
* when block has noreturn statement
|
||||
- avoid emitting defers
|
||||
- compile error for unreachable code
|
||||
|
||||
* detect `return error.Foo` and emit ZIR that unconditionally generates errdefers
|
||||
* `return`: check return operand and generate errdefers if necessary
|
||||
|
||||
* have failed_trees and just put the file in there
|
||||
- this way we can emit all the parse errors not just the first one
|
||||
- but maybe we want just the first one?
|
||||
|
||||
782
src/AstGen.zig
782
src/AstGen.zig
File diff suppressed because it is too large
Load Diff
@ -514,31 +514,26 @@ pub const Scope = struct {
|
||||
pub const NameHash = [16]u8;
|
||||
|
||||
pub fn cast(base: *Scope, comptime T: type) ?*T {
|
||||
if (T == Defer) {
|
||||
switch (base.tag) {
|
||||
.defer_normal, .defer_error => return @fieldParentPtr(T, "base", base),
|
||||
else => return null,
|
||||
}
|
||||
}
|
||||
if (base.tag != T.base_tag)
|
||||
return null;
|
||||
|
||||
return @fieldParentPtr(T, "base", base);
|
||||
}
|
||||
|
||||
/// Returns the arena Allocator associated with the Decl of the Scope.
|
||||
pub fn arena(scope: *Scope) *Allocator {
|
||||
switch (scope.tag) {
|
||||
.block => return scope.cast(Block).?.sema.arena,
|
||||
.gen_zir => return scope.cast(GenZir).?.astgen.arena,
|
||||
.local_val => return scope.cast(LocalVal).?.gen_zir.astgen.arena,
|
||||
.local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.arena,
|
||||
.file => unreachable,
|
||||
.namespace => unreachable,
|
||||
.decl_ref => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ownerDecl(scope: *Scope) ?*Decl {
|
||||
return switch (scope.tag) {
|
||||
.block => scope.cast(Block).?.sema.owner_decl,
|
||||
.gen_zir => unreachable,
|
||||
.local_val => unreachable,
|
||||
.local_ptr => unreachable,
|
||||
.defer_normal => unreachable,
|
||||
.defer_error => unreachable,
|
||||
.file => null,
|
||||
.namespace => null,
|
||||
.decl_ref => scope.cast(DeclRef).?.decl,
|
||||
@ -551,6 +546,8 @@ pub const Scope = struct {
|
||||
.gen_zir => unreachable,
|
||||
.local_val => unreachable,
|
||||
.local_ptr => unreachable,
|
||||
.defer_normal => unreachable,
|
||||
.defer_error => unreachable,
|
||||
.file => null,
|
||||
.namespace => null,
|
||||
.decl_ref => scope.cast(DeclRef).?.decl,
|
||||
@ -564,25 +561,14 @@ pub const Scope = struct {
|
||||
.gen_zir => unreachable,
|
||||
.local_val => unreachable,
|
||||
.local_ptr => unreachable,
|
||||
.defer_normal => unreachable,
|
||||
.defer_error => unreachable,
|
||||
.file => return scope.cast(File).?.namespace,
|
||||
.namespace => return scope.cast(Namespace).?,
|
||||
.decl_ref => return scope.cast(DeclRef).?.decl.namespace,
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts the scope is a child of a `GenZir` and returns it.
|
||||
pub fn getGenZir(scope: *Scope) *GenZir {
|
||||
return switch (scope.tag) {
|
||||
.block => unreachable,
|
||||
.gen_zir => scope.cast(GenZir).?,
|
||||
.local_val => return scope.cast(LocalVal).?.gen_zir,
|
||||
.local_ptr => return scope.cast(LocalPtr).?.gen_zir,
|
||||
.file => unreachable,
|
||||
.namespace => unreachable,
|
||||
.decl_ref => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts the scope has a parent which is a Namespace or File and
|
||||
/// returns the sub_file_path field.
|
||||
pub fn subFilePath(base: *Scope) []const u8 {
|
||||
@ -593,6 +579,8 @@ pub const Scope = struct {
|
||||
.gen_zir => unreachable,
|
||||
.local_val => unreachable,
|
||||
.local_ptr => unreachable,
|
||||
.defer_normal => unreachable,
|
||||
.defer_error => unreachable,
|
||||
.decl_ref => unreachable,
|
||||
}
|
||||
}
|
||||
@ -604,9 +592,11 @@ pub const Scope = struct {
|
||||
cur = switch (cur.tag) {
|
||||
.namespace => return @fieldParentPtr(Namespace, "base", cur).file_scope,
|
||||
.file => return @fieldParentPtr(File, "base", cur),
|
||||
.gen_zir => @fieldParentPtr(GenZir, "base", cur).parent,
|
||||
.local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
|
||||
.local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
|
||||
.gen_zir => return @fieldParentPtr(GenZir, "base", cur).astgen.file,
|
||||
.local_val => return @fieldParentPtr(LocalVal, "base", cur).gen_zir.astgen.file,
|
||||
.local_ptr => return @fieldParentPtr(LocalPtr, "base", cur).gen_zir.astgen.file,
|
||||
.defer_normal => @fieldParentPtr(Defer, "base", cur).parent,
|
||||
.defer_error => @fieldParentPtr(Defer, "base", cur).parent,
|
||||
.block => return @fieldParentPtr(Block, "base", cur).src_decl.namespace.file_scope,
|
||||
.decl_ref => return @fieldParentPtr(DeclRef, "base", cur).decl.namespace.file_scope,
|
||||
};
|
||||
@ -634,6 +624,8 @@ pub const Scope = struct {
|
||||
/// `Decl` for use with `srcDecl` and `ownerDecl`.
|
||||
/// Has no parents or children.
|
||||
decl_ref,
|
||||
defer_normal,
|
||||
defer_error,
|
||||
};
|
||||
|
||||
/// The container that structs, enums, unions, and opaques have.
|
||||
@ -1709,7 +1701,7 @@ pub const Scope = struct {
|
||||
pub const LocalVal = struct {
|
||||
pub const base_tag: Tag = .local_val;
|
||||
base: Scope = Scope{ .tag = base_tag },
|
||||
/// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`.
|
||||
/// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.
|
||||
parent: *Scope,
|
||||
gen_zir: *GenZir,
|
||||
name: []const u8,
|
||||
@ -1724,7 +1716,7 @@ pub const Scope = struct {
|
||||
pub const LocalPtr = struct {
|
||||
pub const base_tag: Tag = .local_ptr;
|
||||
base: Scope = Scope{ .tag = base_tag },
|
||||
/// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`.
|
||||
/// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.
|
||||
parent: *Scope,
|
||||
gen_zir: *GenZir,
|
||||
name: []const u8,
|
||||
@ -1733,6 +1725,13 @@ pub const Scope = struct {
|
||||
token_src: ast.TokenIndex,
|
||||
};
|
||||
|
||||
pub const Defer = struct {
|
||||
base: Scope,
|
||||
/// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.
|
||||
parent: *Scope,
|
||||
defer_node: ast.Node.Index,
|
||||
};
|
||||
|
||||
pub const DeclRef = struct {
|
||||
pub const base_tag: Tag = .decl_ref;
|
||||
base: Scope = Scope{ .tag = base_tag },
|
||||
@ -3821,7 +3820,7 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) In
|
||||
}
|
||||
mod.failed_decls.putAssumeCapacityNoClobber(block.sema.owner_decl, err_msg);
|
||||
},
|
||||
.gen_zir, .local_val, .local_ptr => unreachable,
|
||||
.gen_zir, .local_val, .local_ptr, .defer_normal, .defer_error => unreachable,
|
||||
.file => unreachable,
|
||||
.namespace => unreachable,
|
||||
.decl_ref => {
|
||||
|
||||
37
src/Zir.zig
37
src/Zir.zig
@ -2304,6 +2304,7 @@ const Writer = struct {
|
||||
.byte_swap,
|
||||
.bit_reverse,
|
||||
.elem_type,
|
||||
.bitcast_result_ptr,
|
||||
=> try self.writeUnNode(stream, inst),
|
||||
|
||||
.ref,
|
||||
@ -2424,6 +2425,7 @@ const Writer = struct {
|
||||
.splat,
|
||||
.reduce,
|
||||
.atomic_load,
|
||||
.bitcast,
|
||||
=> try self.writePlNodeBin(stream, inst),
|
||||
|
||||
.call,
|
||||
@ -2509,13 +2511,40 @@ const Writer = struct {
|
||||
.switch_capture_else_ref,
|
||||
=> try self.writeSwitchCapture(stream, inst),
|
||||
|
||||
.bitcast,
|
||||
.bitcast_result_ptr,
|
||||
.extended,
|
||||
=> try stream.writeAll("TODO)"),
|
||||
.extended => try self.writeExtended(stream, inst),
|
||||
}
|
||||
}
|
||||
|
||||
fn writeExtended(self: *Writer, stream: anytype, inst: Inst.Index) !void {
|
||||
const extended = self.code.instructions.items(.data)[inst].extended;
|
||||
try stream.print("{s}(", .{@tagName(extended.opcode)});
|
||||
switch (extended.opcode) {
|
||||
.ret_ptr,
|
||||
.ret_type,
|
||||
.this,
|
||||
.ret_addr,
|
||||
.error_return_trace,
|
||||
.frame,
|
||||
.frame_address,
|
||||
.builtin_src,
|
||||
=> try self.writeExtNode(stream, extended),
|
||||
|
||||
.func,
|
||||
.c_undef,
|
||||
.c_include,
|
||||
.c_define,
|
||||
.wasm_memory_size,
|
||||
.wasm_memory_grow,
|
||||
=> try stream.writeAll("TODO))"),
|
||||
}
|
||||
}
|
||||
|
||||
fn writeExtNode(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
|
||||
const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };
|
||||
try stream.writeAll(")) ");
|
||||
try self.writeSrc(stream, src);
|
||||
}
|
||||
|
||||
fn writeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].bin;
|
||||
try self.writeInstRef(stream, inst_data.lhs);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user