AstGen: basic defer implementation

This commit is contained in:
Andrew Kelley
2021-04-20 16:32:10 -07:00
parent b4aec0e31d
commit a59bcae59f
4 changed files with 546 additions and 349 deletions

View File

@@ -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 => {