Progress in makeScopeInternal
This commit is contained in:
parent
72605c7549
commit
5f5d6ce4ea
282
src/analysis.zig
282
src/analysis.zig
@ -1542,6 +1542,8 @@ fn getDocumentSymbolsInternal(allocator: *std.mem.Allocator, tree: ast.Tree, nod
|
||||
.container_field,
|
||||
.container_field_align,
|
||||
.container_field_init,
|
||||
.tagged_union_enum_tag,
|
||||
.tagged_union_enum_tag_trailing,
|
||||
=> .Field,
|
||||
else => .Variable,
|
||||
},
|
||||
@ -1558,7 +1560,8 @@ fn getDocumentSymbolsInternal(allocator: *std.mem.Allocator, tree: ast.Tree, nod
|
||||
};
|
||||
|
||||
var index: usize = 0;
|
||||
try addOutlineNodes(allocator, tree, node, &child_context);
|
||||
if (true) @panic("FIX: addOutlineNodes");
|
||||
// try addOutlineNodes(allocator, tree, node, &child_context);
|
||||
|
||||
// while (node.iterate(index)) |child| : (index += 1) {
|
||||
// try addOutlineNodes(allocator, tree, child, &child_context);
|
||||
@ -1590,8 +1593,8 @@ pub const Declaration = union(enum) {
|
||||
/// Function parameter
|
||||
param_decl: ast.full.FnProto.Param,
|
||||
pointer_payload: struct {
|
||||
node: ast.full.PtrType,
|
||||
condition: *ast.Node,
|
||||
name: ast.TokenIndex,
|
||||
condition: ast.Node.Index,
|
||||
},
|
||||
array_payload: struct {
|
||||
identifier: *ast.Node,
|
||||
@ -1602,7 +1605,7 @@ pub const Declaration = union(enum) {
|
||||
switch_expr: *ast.Node,
|
||||
items: []const *ast.Node,
|
||||
},
|
||||
label_decl: *ast.Node, // .id is While, For or Block (firstToken will be the label)
|
||||
label_decl: ast.TokenIndex, // .id is While, For or Block (firstToken will be the label)
|
||||
};
|
||||
|
||||
pub const DeclWithHandle = struct {
|
||||
@ -2145,7 +2148,7 @@ fn isContainer(tag: ast.Node.Tag) bool {
|
||||
|
||||
/// Returns the member indices of a given declaration container.
|
||||
/// Asserts given `tag` is a container node
|
||||
fn declMembers(tree: ast.Tree, tag: ast.Node.Tag) []ast.Node.index {
|
||||
fn declMembers(tree: ast.Tree, tag: ast.Node.Tag, node_idx: ast.Node.Index) []const ast.Node.Index {
|
||||
std.debug.assert(isContainer(tag));
|
||||
return switch (tag) {
|
||||
.container_decl, .container_decl_trailing => tree.containerDecl(node_idx).ast.members,
|
||||
@ -2167,6 +2170,18 @@ fn declMembers(tree: ast.Tree, tag: ast.Node.Tag) []ast.Node.index {
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns an `ast.full.VarDecl` for a given node index.
|
||||
/// Returns null if the tag doesn't match
|
||||
fn varDecl(tree: ast.Tree, node_idx: ast.Node.Index) ?ast.full.VarDecl {
|
||||
return switch (tree.nodes.items(.tag)[node_idx]) {
|
||||
.global_var_decl => tree.globalVarDecl(node_idx),
|
||||
.local_var_decl => tree.localVarDecl(node_idx),
|
||||
.aligned_var_decl => tree.alignedVarDecl(node_idx),
|
||||
.simple_var_decl => tree.simpleVarDecl(node_idx),
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO Possibly collect all imports to diff them on changes
|
||||
// as well
|
||||
fn makeScopeInternal(
|
||||
@ -2179,16 +2194,18 @@ fn makeScopeInternal(
|
||||
) error{OutOfMemory}!void {
|
||||
const tags = tree.nodes.items(.tag);
|
||||
const token_tags = tree.tokens.items(.tag);
|
||||
const data = tree.nodes.items(.data);
|
||||
const main_tokens = tree.nodes.items(.main_token);
|
||||
const node = tags[node_idx];
|
||||
|
||||
if (isContainer(node)) {
|
||||
const ast_decls = declMembers(tree, node);
|
||||
const ast_decls = declMembers(tree, node, node_idx);
|
||||
|
||||
(try scopes.addOne(allocator)).* = .{
|
||||
.range = nodeSourceRange(tree, node_idx),
|
||||
.decls = std.StringHashMap(Declaration).init(allocator),
|
||||
// .uses = &[0]*ast.Node.Use{},
|
||||
.tests = &[0]*ast.Node{},
|
||||
.tests = &.{},
|
||||
.data = .{ .container = node_idx },
|
||||
};
|
||||
const scope_idx = scopes.items.len - 1;
|
||||
@ -2227,7 +2244,7 @@ fn makeScopeInternal(
|
||||
};
|
||||
}
|
||||
|
||||
const container_field: ?ast.full.ContainerField = switch (decl) {
|
||||
const container_field: ?ast.full.ContainerField = switch (tags[decl]) {
|
||||
.container_field => tree.containerField(decl),
|
||||
.container_field_align => tree.containerFieldAlign(decl),
|
||||
.container_field_init => tree.containerFieldInit(decl),
|
||||
@ -2235,7 +2252,7 @@ fn makeScopeInternal(
|
||||
};
|
||||
|
||||
if (container_field) |field| {
|
||||
const empty_field = field.type_expr == 0 and field.value_expr == 0;
|
||||
const empty_field = field.ast.type_expr == 0 and field.ast.value_expr == 0;
|
||||
if (empty_field and node == .root) {
|
||||
continue;
|
||||
}
|
||||
@ -2250,7 +2267,7 @@ fn makeScopeInternal(
|
||||
},
|
||||
.tagged_union, .tagged_union_trailing => tree.taggedUnion(node_idx),
|
||||
.tagged_union_enum_tag, .tagged_union_enum_tag_trailing => tree.taggedUnionEnumTag(node_idx),
|
||||
.tagged_union_enum_tag, .tagged_union_enum_tag_trailing => blk: {
|
||||
.tagged_union_two, .tagged_union_two_trailing => blk: {
|
||||
var buffer: [2]ast.Node.Index = undefined;
|
||||
break :blk tree.taggedUnionTwo(&buffer, node_idx);
|
||||
},
|
||||
@ -2287,44 +2304,56 @@ fn makeScopeInternal(
|
||||
}
|
||||
|
||||
switch (node) {
|
||||
.FnProto => {
|
||||
const func = node.castTag(.FnProto).?;
|
||||
.fn_proto, .fn_proto_one, .fn_proto_simple, .fn_proto_multi, .fn_decl => {
|
||||
var buf: [1]ast.Node.Index = undefined;
|
||||
const func: ast.full.FnProto = switch (node) {
|
||||
.fn_proto => tree.fnProto(node_idx),
|
||||
.fn_proto_one => tree.fnProtoOne(&buf, node_idx),
|
||||
.fn_proto_simple => tree.fnProtoSimple(&buf, node_idx),
|
||||
.fn_proto_multi => tree.fnProtoMulti(node_idx),
|
||||
.fn_decl => tree.fnProto(data[node_idx].lhs),
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
(try scopes.addOne(allocator)).* = .{
|
||||
.range = nodeSourceRange(tree, node),
|
||||
.range = nodeSourceRange(tree, node_idx),
|
||||
.decls = std.StringHashMap(Declaration).init(allocator),
|
||||
// .uses = &[0]*ast.Node.Use{},
|
||||
.tests = &[0]*ast.Node{},
|
||||
.tests = &.{},
|
||||
.data = .{ .function = node },
|
||||
};
|
||||
var scope_idx = scopes.items.len - 1;
|
||||
errdefer scopes.items[scope_idx].decls.deinit();
|
||||
|
||||
for (func.params()) |*param| {
|
||||
if (param.name_token) |name_tok| {
|
||||
if (try scopes.items[scope_idx].decls.fetchPut(tree.tokenSlice(name_tok), .{ .param_decl = param })) |existing| {
|
||||
// TODO Record a redefinition error
|
||||
var it = func.iterate(tree);
|
||||
while (it.next()) |param| {
|
||||
if (param.name_token) |name_token| {
|
||||
if (try scopes.items[scope_idx].decls.fetchPut(tree.tokenSlice(name_token), .{ .param_decl = param })) |existing| {
|
||||
// TODO record a redefinition error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (func.getBodyNode()) |body| {
|
||||
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, body);
|
||||
if (node == .fn_decl) {
|
||||
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, data[node_idx].rhs);
|
||||
}
|
||||
|
||||
return;
|
||||
},
|
||||
.TestDecl => {
|
||||
return try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, node.castTag(.TestDecl).?.body_node);
|
||||
.test_decl => {
|
||||
return try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, data[node_idx].rhs);
|
||||
},
|
||||
.LabeledBlock => {
|
||||
const block = node.castTag(.LabeledBlock).?;
|
||||
std.debug.assert(tree.token_ids[block.label] == .Identifier);
|
||||
var scope = try scopes.addOne(allocator);
|
||||
.block, .block_semicolon, .block_two, .block_two_semicolon => {
|
||||
const first_token = tree.firstToken(node_idx);
|
||||
const last_token = tree.lastToken(node_idx);
|
||||
|
||||
// if labeled block
|
||||
if (token_tags[first_token] == .identifier) {
|
||||
const scope = try scopes.addOne(allocator);
|
||||
scope.* = .{
|
||||
.range = .{
|
||||
.start = tree.token_locs[block.lbrace].start,
|
||||
.end = tree.token_locs[block.rbrace].end,
|
||||
.start = tree.tokenLocation(main_tokens[node_idx]).line_start,
|
||||
.end = tree.tokenLocation(@truncate(u32, start), last_token).line_start,
|
||||
},
|
||||
.decls = std.StringHashMap(Declaration).init(allocator),
|
||||
// .uses = &[0]*ast.Node.Use{},
|
||||
@ -2332,17 +2361,15 @@ fn makeScopeInternal(
|
||||
.data = .other,
|
||||
};
|
||||
errdefer scope.decls.deinit();
|
||||
|
||||
try scope.decls.putNoClobber(tree.tokenSlice(block.label), .{
|
||||
.label_decl = node,
|
||||
});
|
||||
try scopes.items[scope_idx].decls.putNoClobber(tree.tokenSlice(first_token), .{ .label_decl = first_token });
|
||||
}
|
||||
|
||||
(try scopes.addOne(allocator)).* = .{
|
||||
.range = nodeSourceRange(tree, node),
|
||||
.range = nodeSourceRange(tree, node_idx),
|
||||
.decls = std.StringHashMap(Declaration).init(allocator),
|
||||
// .uses = &[0]*ast.Node.Use{},
|
||||
.tests = &[0]*ast.Node{},
|
||||
.data = .{ .block = node },
|
||||
.tests = &.{},
|
||||
.data = .{ .block = node_idx },
|
||||
};
|
||||
var scope_idx = scopes.items.len - 1;
|
||||
// var uses = std.ArrayList(*ast.Node.Use).init(allocator);
|
||||
@ -2352,18 +2379,23 @@ fn makeScopeInternal(
|
||||
// uses.deinit();
|
||||
}
|
||||
|
||||
var child_idx: usize = 0;
|
||||
while (node.iterate(child_idx)) |child_node| : (child_idx += 1) {
|
||||
// if (child_node.castTag(.Use)) |use| {
|
||||
// try uses.append(use);
|
||||
// continue;
|
||||
// }
|
||||
const statements: []const ast.Node.Index = switch (node) {
|
||||
.block, .block_semicolon => tree.extra_data[data[node_idx].lhs..data[node_idx].rhs],
|
||||
.block_two, .block_two_semicolon => blk: {
|
||||
const statements = [2]ast.Node.Index{ data[node_idx].lhs, data[node_idx].rhs };
|
||||
const len: usize = if (data[node_idx].lhs == 0) 0 else if (data[node_idx].rhs == 0) 1 else 2;
|
||||
break :blk statements[0..len];
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, child_node);
|
||||
if (child_node.castTag(.VarDecl)) |var_decl| {
|
||||
const name = tree.tokenSlice(var_decl.name_token);
|
||||
if (try scopes.items[scope_idx].decls.fetchPut(name, .{ .ast_node = child_node })) |existing| {
|
||||
// TODO Record a redefinition error.
|
||||
for (statements[0..len]) |idx| {
|
||||
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, idx);
|
||||
// if (tags[
|
||||
if (varDecl(idx)) |var_decl| {
|
||||
const name = tree.tokenSlice(var_decl.ast.mut_token + 1);
|
||||
if (try scopes.items[scope_idx].decls.fetchPut(name, .{ .ast_node = idx })) |existing| {
|
||||
// TODO record a redefinition error.
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2371,171 +2403,139 @@ fn makeScopeInternal(
|
||||
// scopes.items[scope_idx].uses = uses.toOwnedSlice();
|
||||
return;
|
||||
},
|
||||
.Block => {
|
||||
const block = node.castTag(.Block).?;
|
||||
|
||||
(try scopes.addOne(allocator)).* = .{
|
||||
.range = nodeSourceRange(tree, node),
|
||||
.decls = std.StringHashMap(Declaration).init(allocator),
|
||||
// .uses = &[0]*ast.Node.Use{},
|
||||
.tests = &[0]*ast.Node{},
|
||||
.data = .{ .block = node },
|
||||
};
|
||||
var scope_idx = scopes.items.len - 1;
|
||||
// var uses = std.ArrayList(*ast.Node.Use).init(allocator);
|
||||
|
||||
errdefer {
|
||||
scopes.items[scope_idx].decls.deinit();
|
||||
// uses.deinit();
|
||||
}
|
||||
|
||||
var child_idx: usize = 0;
|
||||
while (node.iterate(child_idx)) |child_node| : (child_idx += 1) {
|
||||
// if (child_node.castTag(.Use)) |use| {
|
||||
// try uses.append(use);
|
||||
// continue;
|
||||
// }
|
||||
|
||||
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, child_node);
|
||||
if (child_node.castTag(.VarDecl)) |var_decl| {
|
||||
const name = tree.tokenSlice(var_decl.name_token);
|
||||
if (try scopes.items[scope_idx].decls.fetchPut(name, .{ .ast_node = child_node })) |existing| {
|
||||
// TODO Record a redefinition error.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// scopes.items[scope_idx].uses = uses.toOwnedSlice();
|
||||
return;
|
||||
.@"comptime", .@"nosuspend" => {
|
||||
return try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, data[node_idx].lhs);
|
||||
},
|
||||
.Comptime => {
|
||||
return try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, node.castTag(.Comptime).?.expr);
|
||||
},
|
||||
.If => {
|
||||
const if_node = node.castTag(.If).?;
|
||||
.@"if", .if_simple => {
|
||||
const if_node: ast.full.If = if (node == .@"if")
|
||||
tree.ifFull(node_idx)
|
||||
else
|
||||
tree.ifSimple(node_idx);
|
||||
|
||||
if (if_node.payload) |payload| {
|
||||
std.debug.assert(payload.tag == .PointerPayload);
|
||||
if (if_node.payload_token) |payload| {
|
||||
var scope = try scopes.addOne(allocator);
|
||||
scope.* = .{
|
||||
.range = .{
|
||||
.start = tree.token_locs[payload.firstToken()].start,
|
||||
.end = tree.token_locs[if_node.body.lastToken()].end,
|
||||
.start = tree.tokenLocation(0, payload).line_start,
|
||||
.end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(if_node.ast.then_expr)).line_end,
|
||||
},
|
||||
.decls = std.StringHashMap(Declaration).init(allocator),
|
||||
// .uses = &[0]*ast.Node.Use{},
|
||||
.tests = &[0]*ast.Node{},
|
||||
.tests = &.{},
|
||||
.data = .other,
|
||||
};
|
||||
errdefer scope.decls.deinit();
|
||||
|
||||
const ptr_payload = payload.castTag(.PointerPayload).?;
|
||||
std.debug.assert(ptr_payload.value_symbol.tag == .Identifier);
|
||||
const name = tree.tokenSlice(ptr_payload.value_symbol.firstToken());
|
||||
const name_token = payload + @boolToInt(token_tags[payload] == .asterisk);
|
||||
std.debug.assert(token_tags[name_token] == .identifier);
|
||||
|
||||
const name = tree.tokenSlice(name_token);
|
||||
try scope.decls.putNoClobber(name, .{
|
||||
.pointer_payload = .{
|
||||
.node = ptr_payload,
|
||||
.condition = if_node.condition,
|
||||
.name = name_token,
|
||||
.condition = if_node.ast.cond_expr,
|
||||
},
|
||||
});
|
||||
}
|
||||
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, if_node.body);
|
||||
|
||||
if (if_node.@"else") |else_node| {
|
||||
if (else_node.payload) |payload| {
|
||||
std.debug.assert(payload.tag == .Payload);
|
||||
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, if_node.ast.then_expr);
|
||||
|
||||
if (if_node.ast.else_expr != 0) {
|
||||
if (if_node.error_token) |err_token| {
|
||||
std.debug.assert(token_tags[err_token] == .identifier);
|
||||
var scope = try scopes.addOne(allocator);
|
||||
scope.* = .{
|
||||
.range = .{
|
||||
.start = tree.token_locs[payload.firstToken()].start,
|
||||
.end = tree.token_locs[else_node.body.lastToken()].end,
|
||||
.start = tree.tokenLocation(0, err_token).line_start,
|
||||
.end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(if_node.ast.else_expr)).line_end,
|
||||
},
|
||||
.decls = std.StringHashMap(Declaration).init(allocator),
|
||||
// .uses = &[0]*ast.Node.Use{},
|
||||
.tests = &[0]*ast.Node{},
|
||||
.tests = &.{},
|
||||
.data = .other,
|
||||
};
|
||||
errdefer scope.decls.deinit();
|
||||
|
||||
const err_payload = payload.castTag(.Payload).?;
|
||||
std.debug.assert(err_payload.error_symbol.tag == .Identifier);
|
||||
const name = tree.tokenSlice(err_payload.error_symbol.firstToken());
|
||||
try scope.decls.putNoClobber(name, .{ .ast_node = payload });
|
||||
const name = tree.tokenSlice(err_token);
|
||||
try scope.decls.putNoClobber(name, .{ .ast_node = if_node.ast.else_expr });
|
||||
}
|
||||
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, else_node.body);
|
||||
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, if_node.ast.else_expr);
|
||||
}
|
||||
},
|
||||
.While => {
|
||||
const while_node = node.castTag(.While).?;
|
||||
if (while_node.label) |label| {
|
||||
std.debug.assert(tree.token_ids[label] == .Identifier);
|
||||
.@"while", .while_simple, .while_cont, .@"for", .for_simple => {
|
||||
const while_node: ast.full.While = switch (node) {
|
||||
.@"while" => tree.whileFull(node_idx),
|
||||
.while_simple => tree.whileSimple(node_idx),
|
||||
.while_cont => tree.whileCont(node_idx),
|
||||
.@"for" => tree.forFull(node_idx),
|
||||
.for_simple => tree.forSimple(node_idx),
|
||||
else => unreachable,
|
||||
};
|
||||
if (while_node.label_token) |label| {
|
||||
std.debug.assert(tags[label] == .identifier);
|
||||
var scope = try scopes.addOne(allocator);
|
||||
scope.* = .{
|
||||
.range = .{
|
||||
.start = tree.token_locs[while_node.while_token].start,
|
||||
.end = tree.token_locs[while_node.lastToken()].end,
|
||||
.start = tree.tokenLocation(0, main_tokens[node_idx]).line_start,
|
||||
.end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(while_node.ast.then_expr)).line_end,
|
||||
},
|
||||
.decls = std.StringHashMap(Declaration).init(allocator),
|
||||
// .uses = &[0]*ast.Node.Use{},
|
||||
.tests = &[0]*ast.Node{},
|
||||
.tests = &.{},
|
||||
.data = .other,
|
||||
};
|
||||
errdefer scope.decls.deinit();
|
||||
|
||||
try scope.decls.putNoClobber(tree.tokenSlice(label), .{
|
||||
.label_decl = node,
|
||||
});
|
||||
try scope.decls.putNoClobber(tree.tokenSlice(label), .{ .label_decl = label });
|
||||
}
|
||||
|
||||
if (while_node.payload) |payload| {
|
||||
std.debug.assert(payload.tag == .PointerPayload);
|
||||
if (while_node.payload_token) |payload| {
|
||||
var scope = try scopes.addOne(allocator);
|
||||
scope.* = .{
|
||||
.range = .{
|
||||
.start = tree.token_locs[payload.firstToken()].start,
|
||||
.end = tree.token_locs[while_node.body.lastToken()].end,
|
||||
.start = tree.tokenLocation(0, payload).line_start,
|
||||
.end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(while_node.ast.then_exp)).line_end,
|
||||
},
|
||||
.decls = std.StringHashMap(Declaration).init(allocator),
|
||||
// .uses = &[0]*ast.Node.Use{},
|
||||
.tests = &[0]*ast.Node{},
|
||||
.tests = &.{},
|
||||
.data = .other,
|
||||
};
|
||||
errdefer scope.decls.deinit();
|
||||
|
||||
const ptr_payload = payload.castTag(.PointerPayload).?;
|
||||
std.debug.assert(ptr_payload.value_symbol.tag == .Identifier);
|
||||
const name = tree.tokenSlice(ptr_payload.value_symbol.firstToken());
|
||||
const name_token = payload + @boolToInt(token_tags[payload] == .asterisk);
|
||||
std.debug.assert(token_tags[name_token] == .identifier);
|
||||
|
||||
const name = tree.tokenSlice(name_token);
|
||||
try scope.decls.putNoClobber(name, .{
|
||||
.pointer_payload = .{
|
||||
.node = ptr_payload,
|
||||
.condition = while_node.condition,
|
||||
.name = name_token,
|
||||
.condition = while_node.ast.cond_expr,
|
||||
},
|
||||
});
|
||||
}
|
||||
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, while_node.body);
|
||||
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, while_node.ast.then_expr);
|
||||
|
||||
if (while_node.@"else") |else_node| {
|
||||
if (else_node.payload) |payload| {
|
||||
std.debug.assert(payload.tag == .Payload);
|
||||
if (while_node.ast.else_expr != 0) {
|
||||
if (while_node.error_token) |err_token| {
|
||||
std.debug.assert(token_tags[err_token] == .identifier);
|
||||
var scope = try scopes.addOne(allocator);
|
||||
scope.* = .{
|
||||
.range = .{
|
||||
.start = tree.token_locs[payload.firstToken()].start,
|
||||
.end = tree.token_locs[else_node.body.lastToken()].end,
|
||||
.start = tree.tokenLocation(0, err_token).line_start,
|
||||
.end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(if_node.ast.else_expr)).line_end,
|
||||
},
|
||||
.decls = std.StringHashMap(Declaration).init(allocator),
|
||||
// .uses = &[0]*ast.Node.Use{},
|
||||
.tests = &[0]*ast.Node{},
|
||||
.tests = &.{},
|
||||
.data = .other,
|
||||
};
|
||||
errdefer scope.decls.deinit();
|
||||
|
||||
const err_payload = payload.castTag(.Payload).?;
|
||||
std.debug.assert(err_payload.error_symbol.tag == .Identifier);
|
||||
const name = tree.tokenSlice(err_payload.error_symbol.firstToken());
|
||||
try scope.decls.putNoClobber(name, .{ .ast_node = payload });
|
||||
const name = tree.tokenSlice(err_token);
|
||||
try scope.decls.putNoClobber(name, .{ .ast_node = if_node.ast.else_expr });
|
||||
}
|
||||
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, else_node.body);
|
||||
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, while_node.ast.else_expr);
|
||||
}
|
||||
},
|
||||
.For => {
|
||||
|
Loading…
Reference in New Issue
Block a user