From 18067920877c2ac98987f24bcdd0a6213f4c72fa Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Wed, 20 Nov 2024 12:57:05 -0500 Subject: [PATCH] feat(semantic): record symbol references (#86) --- src/printer/Printer.zig | 5 + src/printer/SemanticPrinter.zig | 60 ++- src/semantic.zig | 1 + src/semantic/Reference.zig | 171 +++++++++ src/semantic/Scope.zig | 96 ++++- src/semantic/Semantic.zig | 31 +- src/semantic/SemanticBuilder.zig | 341 +++++++++++++++++- src/semantic/Symbol.zig | 75 +++- src/semantic/id.zig | 7 + test/semantic/snapshot_coverage.zig | 4 + .../simple/pass/block.zig.snap | 56 +++ .../simple/pass/block_comptime.zig.snap | 12 + .../simple/pass/cond_if.zig.snap | 35 ++ .../simple/pass/enum_members.zig.snap | 24 ++ .../simple/pass/fibonacci.zig.snap | 58 +++ .../simple/pass/fn_comptime.zig.snap | 39 ++ .../simple/pass/fn_in_fn.zig.snap | 14 + .../simple/pass/foo.zig.snap | 27 ++ .../simple/pass/loops_for.zig.snap | 27 ++ .../simple/pass/loops_while.zig.snap | 73 ++++ .../simple/pass/struct_members.zig.snap | 16 + .../simple/pass/top_level_struct.zig.snap | 16 + .../simple/pass/unresolved_import.zig.snap | 7 + .../simple/pass/writer_interface.zig.snap | 41 +++ 24 files changed, 1195 insertions(+), 41 deletions(-) create mode 100644 src/semantic/Reference.zig diff --git a/src/printer/Printer.zig b/src/printer/Printer.zig index 1e6ddcf..081e3a7 100644 --- a/src/printer/Printer.zig +++ b/src/printer/Printer.zig @@ -72,6 +72,11 @@ pub fn pPropJson(self: *Printer, key: []const u8, value: anytype) !void { try self.pIndent(); } +pub fn pJson(self: *Printer, value: anytype) !void { + const options: std.json.StringifyOptions = .{}; + try stringify(value, options, self.writer); +} + /// Print an object property key with a trailing `:`, without printing a value. pub fn pPropName(self: *Printer, key: []const u8) !void { try self.pString(key); diff --git a/src/printer/SemanticPrinter.zig b/src/printer/SemanticPrinter.zig index 66e65af..6e6daf9 100644 --- a/src/printer/SemanticPrinter.zig +++ b/src/printer/SemanticPrinter.zig @@ -32,10 +32,58 @@ fn printSymbol(self: *SemanticPrinter, symbol: *const Semantic.Symbol, symbols: try self.printer.pPropWithNamespacedValue("declNode", decl); try self.printer.pProp("scope", "{d}", symbol.scope); try self.printer.pPropJson("flags", symbol.flags); + + { + try self.printer.pPropName("references"); + try self.printer.pushArray(); + defer { + self.printer.pop(); + self.printer.pIndent() catch @panic("print failed"); + } + for (symbol.references.items) |ref_id| { + try self.printReference(ref_id); + self.printer.pComma(); + try self.printer.pIndent(); + } + } + try self.printer.pPropJson("members", @as([]u32, @ptrCast(symbols.getMembers(symbol.id).items))); try self.printer.pPropJson("exports", @as([]u32, @ptrCast(symbols.getExports(symbol.id).items))); } +pub fn printUnresolvedReferences(self: *SemanticPrinter) !void { + const p = self.printer; + const symbols = &self.semantic.symbols; + + if (symbols.unresolved_references.items.len == 0) { + try p.print("[],", .{}); + return; + } + + try p.pushArray(); + defer p.pop(); + for (symbols.unresolved_references.items) |ref_id| { + try self.printReference(ref_id); + self.printer.pComma(); + try self.printer.pIndent(); + } +} + +fn printReference(self: *SemanticPrinter, ref_id: Reference.Id) !void { + const ref = self.semantic.symbols.getReference(ref_id); + const tags = self.semantic.ast.nodes.items(.tag); + + const sid: ?Symbol.Id.Repr = if (ref.symbol.unwrap()) |id| id.int() else null; + const printable = PrintableReference{ + .symbol = sid, + .scope = ref.scope.int(), + .node = tags[ref.node], + .identifier = ref.identifier, + .flags = ref.flags, + }; + try self.printer.pJson(printable); +} + pub fn printScopeTree(self: *SemanticPrinter) !void { return self.printScope(&self.semantic.scopes.getScope(Semantic.ROOT_SCOPE_ID)); } @@ -54,7 +102,6 @@ fn printScope(self: *SemanticPrinter, scope: *const Semantic.Scope) !void { try p.pProp("id", "{d}", scope.id); - // try p.pPropJson("flags", scope.flags); { const f = scope.flags; try p.pPropName("flags"); @@ -113,6 +160,14 @@ fn printStrIf(p: *Printer, str: []const u8, cond: bool) !void { try p.pIndent(); } +const PrintableReference = struct { + symbol: ?Symbol.Id.Repr, + scope: Scope.Id.Repr, + node: Node.Tag, + identifier: []const u8, + flags: Reference.Flags, +}; + const SemanticPrinter = @This(); const std = @import("std"); @@ -123,3 +178,6 @@ const _semantic = @import("../semantic.zig"); const SemanticBuilder = _semantic.Builder; const Semantic = _semantic.Semantic; const Symbol = _semantic.Symbol; +const Scope = _semantic.Scope; +const Reference = _semantic.Reference; +const Node = std.zig.Ast.Node; diff --git a/src/semantic.zig b/src/semantic.zig index fb6dba7..06247b4 100644 --- a/src/semantic.zig +++ b/src/semantic.zig @@ -17,5 +17,6 @@ pub const Symbol = @import("./semantic/Symbol.zig"); pub const SymbolTable = Symbol.SymbolTable; pub const Scope = @import("./semantic/Scope.zig"); pub const ScopeTree = Scope.ScopeTree; +pub const Reference = @import("./semantic/Reference.zig"); const std = @import("std"); diff --git a/src/semantic/Reference.zig b/src/semantic/Reference.zig new file mode 100644 index 0000000..9d92349 --- /dev/null +++ b/src/semantic/Reference.zig @@ -0,0 +1,171 @@ +//! A reference on a symbol. Describes where and how a symbol is used. + +pub const Reference = @This(); + +symbol: Symbol.Id.Optional, +scope: Scope.Id, +node: Node.Index, +identifier: []const u8, +flags: Flags, + +pub const Id = NominalId(u32); + +const FLAGS_REPR = u8; + +/// Describes how a reference uses a symbol. +/// +/// ## Chained references +/// ```zig +/// const x = foo.bar.baz() +/// ``` +/// - `foo` is `member | read` +/// - `bar` is `member | call` +/// - `baz` is `call` +pub const Flags = packed struct(FLAGS_REPR) { + /// Reference is reading a symbol's value. + read: bool = false, + /// Reference is modifying the value stored in a symbol. + write: bool = false, + /// Reference is calling the symbol as a function. + call: bool = false, + /// Reference is using the symbol in a type annotation or function signature. + /// + /// Does not include type parameters. + type: bool = false, + /// Reference is on a field member. + /// + /// Mixed together with other flags to indicate how the member is being used. + /// Make sure this is `false` if you want to check that a symbol is, itself, + /// being read/written/etc. + member: bool = false, + // Padding. + _: u3 = 0, + + pub fn eq(self: Flags, other: Flags) bool { + const a: FLAGS_REPR = @bitCast(self); + const b: FLAGS_REPR = @bitCast(other); + return a == b; + } + + pub fn merge(self: Flags, other: Flags) Flags { + const a: FLAGS_REPR = @bitCast(self); + const b: FLAGS_REPR = @bitCast(other); + + return @bitCast(a | b); + } + + pub fn contains(self: Flags, other: Flags) bool { + const a: FLAGS_REPR = @bitCast(self); + const b: FLAGS_REPR = @bitCast(other); + return (a & b) == b; + } + + pub fn intersects(self: Flags, other: Flags) bool { + const a: FLAGS_REPR = @bitCast(self); + const b: FLAGS_REPR = @bitCast(other); + return (a | b) > 0; + } + + /// `true` if the referenced symbol is having its value read. + /// + /// ```zig + /// const y = foo; + /// // ^^^ + /// ``` + pub inline fn isSelfRead(f: Flags) bool { + return !f.member and f.read; + } + + /// `true` if the referenced symbol is having its value modified. + /// ```zig + /// const y = foo + 1; + /// // ^^^ + /// ``` + pub inline fn isSelfWrite(f: Flags) bool { + return !f.member and f.write; + } + + /// `true` if the referenced symbol is being called. + /// + /// ```zig + /// const y = foo(); + /// // ^^^^^ + /// ``` + pub inline fn isSelfCall(f: Flags) bool { + return !f.member and f.call; + } + + /// `true` if the referenced symbol is being used in a type annotation. + /// + /// ```zig + /// const y: Foo = .{}; + /// // ^^^ + /// ``` + pub inline fn isSelfType(f: Flags) bool { + return !f.member and f.type; + } + + /// `true` if this symbol is having one of its members read. + /// + /// ```zig + /// const y = foo.x; + /// // ^^^ + /// ``` + pub inline fn isMemberRead(f: Flags) bool { + return f.member and f.read; + } + + /// `true` if this symbol is having one of its members modified. + /// + /// ```zig + /// const y = foo.x + 1; + /// // ^^^ + /// ``` + pub inline fn isMemberWrite(f: Flags) bool { + return f.member and f.write; + } + + /// `true` if this symbol is having one of its members called as a function. + /// + /// ```zig + /// const y = foo.x(); + /// // ^^^ + /// ``` + pub inline fn isMemberCall(f: Flags) bool { + return f.member and f.call; + } + + /// `true` if this symbol is having one of its members used in a type annotation. + /// + /// ```zig + /// const y: mod.Foo = .{}; + /// // ^^^ + /// ``` + pub inline fn isMemberType(f: Flags) bool { + return f.member and f.type; + } +}; + +const std = @import("std"); +const NominalId = @import("id.zig").NominalId; + +const Node = std.zig.Ast.Node; +const Scope = @import("Scope.zig"); +const Symbol = @import("Symbol.zig"); + +const t = std.testing; +test { + t.refAllDecls(@This()); + t.refAllDecls(Reference); +} + +test "Flags.isMemberRead" { + try t.expect(Flags.isMemberRead(.{ .member = true, .read = true })); + try t.expect(Flags.isMemberRead(.{ .member = true, .read = true, .write = true })); + + // zig fmt: off + try t.expect(!Flags.isMemberRead(.{ .member = true, .write = true })); + try t.expect(!Flags.isMemberRead(.{ .member = false, .read = true })); + try t.expect(!Flags.isMemberRead(.{ .member = true, .read = false })); + // zig fmt: on +} diff --git a/src/semantic/Scope.zig b/src/semantic/Scope.zig index 0c050fa..49e4423 100644 --- a/src/semantic/Scope.zig +++ b/src/semantic/Scope.zig @@ -2,7 +2,7 @@ id: Id, /// Scope hints. flags: Flags, -parent: ?Id, +parent: Id.Optional, /// Uniquely identifies a scope within a source file. pub const Id = NominalId(u32); @@ -49,6 +49,14 @@ pub const Flags = packed struct(FLAGS_REPR) { const b: FLAGS_REPR = @bitCast(other); return @bitCast(a | b); } + + /// Returns `true` if two sets of flags have exactly the same flags + /// enabled/diabled. + pub fn eq(self: Flags, other: Flags) bool { + const a: FLAGS_REPR = @bitCast(self); + const b: FLAGS_REPR = @bitCast(other); + return a == b; + } }; /// Stores variable scopes created by a zig program. @@ -63,6 +71,20 @@ pub const ScopeTree = struct { const ScopeIdList = std.ArrayListUnmanaged(Scope.Id); const SymbolIdList = std.ArrayListUnmanaged(Symbol.Id); + /// Returns the number of declared scopes in a program. + /// + /// Shorthand for `scope_tree.scopes.len`. + pub inline fn len(self: *const ScopeTree) u32 { + @setRuntimeSafety(!util.IS_DEBUG); + assert(self.scopes.len < Id.MAX); + + return @intCast(self.scopes.len); + } + + /// Get all properties of a scope by ID. + /// + /// Avoid this when possible. Prefer using property slices for better cache + /// locality. pub fn getScope(self: *const ScopeTree, id: Scope.Id) Scope { return self.scopes.get(id.into(usize)); } @@ -78,7 +100,7 @@ pub const ScopeTree = struct { // initialize the new scope try self.scopes.append(alloc, Scope{ .id = id, - .parent = parent, + .parent = Id.Optional.from(parent), .flags = flags, }); @@ -104,19 +126,26 @@ pub const ScopeTree = struct { return self.bindings.items[scope_id.int()].append(alloc, symbol_id); } + pub fn getBindings(self: *const ScopeTree, scope_id: Scope.Id) []const Symbol.Id { + return self.bindings.items[scope_id.int()].items; + } + + pub fn iterParents(self: *const ScopeTree, scope_id: Scope.Id) ScopeParentIterator { + return .{ + .curr = scope_id.into(Id.Optional), + .parents = self.scopes.items(.parent), + }; + } + pub fn deinit(self: *ScopeTree, alloc: Allocator) void { self.scopes.deinit(alloc); - { - var i: usize = 0; - const len = self.children.items.len; - while (i < len) { - var children = self.children.items[i]; - children.deinit(alloc); - i += 1; - } - self.children.deinit(alloc); + for (0..self.children.items.len) |i| { + var children = self.children.items[i]; + children.deinit(alloc); } + self.children.deinit(alloc); + for (0..self.bindings.items.len) |i| { self.bindings.items[i].deinit(alloc); } @@ -124,32 +153,50 @@ pub const ScopeTree = struct { } }; +const ScopeParentIterator = struct { + curr: Scope.Id.Optional, + // tree: *const ScopeTree, + parents: []const Id.Optional, + + pub fn next(self: *ScopeParentIterator) ?Scope.Id { + // const parents = self.tree.scopes.items(.parent); + const curr = self.curr.unwrap(); + if (curr) |c| { + self.curr = self.parents[c.int()]; + } + return curr; + } +}; + const Scope = @This(); const std = @import("std"); +const util = @import("util"); const Allocator = std.mem.Allocator; const Ast = std.zig.Ast; const Type = std.builtin.Type; const Symbol = @import("Symbol.zig"); const NominalId = @import("id.zig").NominalId; -const string = @import("util").string; +const string = util.string; const assert = std.debug.assert; +const t = std.testing; + test Flags { const block = Flags{ .s_block = true }; const top = Flags{ .s_top = true }; const empty = Flags{}; - try std.testing.expectEqual(Flags{ .s_block = true, .s_top = true }, block.merge(top)); + try t.expectEqual(Flags{ .s_block = true, .s_top = true }, block.merge(top)); - try std.testing.expectEqual(block, block.merge(empty)); - try std.testing.expectEqual(block, block.merge(block)); - try std.testing.expectEqual(block, block.merge(.{ .s_block = false })); + try t.expectEqual(block, block.merge(empty)); + try t.expectEqual(block, block.merge(block)); + try t.expectEqual(block, block.merge(.{ .s_block = false })); } test "ScopeTree.addScope" { - const alloc = std.testing.allocator; - const expectEqual = std.testing.expectEqual; + const alloc = t.allocator; + const expectEqual = t.expectEqual; var tree = ScopeTree{}; defer tree.deinit(alloc); @@ -166,7 +213,7 @@ test "ScopeTree.addScope" { const child = tree.getScope(child_id); try expectEqual(1, child.id.int()); try expectEqual(Scope.Flags{}, child.flags); - try expectEqual(root.id, child.parent); + try expectEqual(root.id, child.parent.unwrap().?); try expectEqual(child, tree.scopes.get(1)); try expectEqual(2, tree.scopes.len); @@ -174,3 +221,14 @@ test "ScopeTree.addScope" { try expectEqual(1, tree.children.items[0].items.len); try expectEqual(1, tree.children.items[0].items[0].int()); } + +test "Flags.merge" { + const expected = Flags{ .s_block = true, .s_enum = true }; + const a = Flags{ .s_block = true }; + + var result = a.merge(.{ .s_enum = true }); + try t.expect(expected.eq(result)); + + result = a.merge(.{ .s_enum = true, .s_comptime = true }); + try t.expect(!expected.eq(result)); +} diff --git a/src/semantic/Semantic.zig b/src/semantic/Semantic.zig index fd84a0a..79c472b 100644 --- a/src/semantic/Semantic.zig +++ b/src/semantic/Semantic.zig @@ -32,6 +32,32 @@ pub const ROOT_NODE_ID: Ast.Node.Index = 0; /// Alias for `ROOT_NODE_ID`. Used in null-node check contexts for code clarity. pub const NULL_NODE: Ast.Node.Index = ROOT_NODE_ID; +/// Find the symbol bound to an identifier name that was declared in some scope. +/// +/// To find a binding that is referrable within a scope, but that may not have +/// been declared in it, use `resolveBinding`. +pub fn getBinding(self: *const Semantic, scope_id: Scope.Id, name: []const u8) ?Symbol.Id { + const bindings = self.scopes.getBindings(scope_id); + const names = self.symbols.symbols.items(.name); + for (bindings) |symbol_id| { + if (std.mem.eql(u8, names[symbol_id.into(usize)], name)) { + return symbol_id; + } + } + return null; +} + +/// Find an in-scope symbol bound to an identifier name. +/// +/// To only find symbols declared within a scope, use `getBinding`. +pub fn resolveBinding(self: *const Semantic, scope_id: Scope.Id, name: []const u8) ?Symbol.Id { + var it = self.scopes.iterParents(scope_id); + while (it.next()) |scope| { + if (self.getBinding(scope, name)) |binding| return binding; + } + return null; +} + pub fn deinit(self: *Semantic) void { // NOTE: ast is arena allocated, so no need to deinit it. freeing the arena // is sufficient. @@ -53,10 +79,11 @@ const Type = std.builtin.Type; const assert = std.debug.assert; pub const NodeLinks = @import("NodeLinks.zig"); -pub const Scope = @import("./Scope.zig"); +pub const Scope = @import("Scope.zig"); pub const ScopeTree = Scope.ScopeTree; -pub const Symbol = @import("./Symbol.zig"); +pub const Symbol = @import("Symbol.zig"); pub const SymbolTable = Symbol.SymbolTable; +pub const Reference = @import("Reference.zig"); const util = @import("util"); const string = util.string; diff --git a/src/semantic/SemanticBuilder.zig b/src/semantic/SemanticBuilder.zig index 3a9dee7..71579c2 100644 --- a/src/semantic/SemanticBuilder.zig +++ b/src/semantic/SemanticBuilder.zig @@ -13,6 +13,7 @@ _arena: ArenaAllocator, _curr_scope_id: Semantic.Scope.Id = ROOT_SCOPE, _curr_symbol_id: ?Semantic.Symbol.Id = null, _curr_scope_flags: Scope.Flags = .{}, +_curr_reference_flags: Reference.Flags = .{ .read = true }, // stacks @@ -21,8 +22,15 @@ _scope_stack: std.ArrayListUnmanaged(Semantic.Scope.Id) = .{}, /// is pushed here. This lets us record members and exports. _symbol_stack: std.ArrayListUnmanaged(Semantic.Symbol.Id) = .{}, _node_stack: std.ArrayListUnmanaged(NodeIndex) = .{}, +/// References encountered but that could not be resolved. Includes references +/// that occur before symbol declaration, and we haven't seen the declaration yet. +/// After analysis, references in this list are to symbols not declared anywhere +/// in the source. +/// +/// We try to resolve these each time a scope is exited. +_unresolved_references: ReferenceStack = .{}, -/// SAFETY: initialized after parsing. Same safety rationale as _root_scope. +/// SAFETY: initialized after parsing. _semantic: Semantic = undefined, /// Errors encountered during parsing and analysis. /// @@ -100,6 +108,28 @@ pub fn build(builder: *SemanticBuilder, source: stringSlice) SemanticError!Resul builder.assertRoot(); } + // resolve references to symbols declared in root + try builder.resolveReferencesInCurrentScope(); + // Take whatever references still haven't been resolved and move them to + // Semantic. + switch (builder._unresolved_references.len()) { + 0 => builder._semantic.symbols.unresolved_references = .{}, + 1 => { + const unresolved = try builder._unresolved_references.curr().toOwnedSlice(builder._gpa); + builder._semantic.symbols.unresolved_references = .{ + .items = unresolved, + .capacity = unresolved.len, + }; + }, + else => { + util.assert( + builder._unresolved_references.len() == 1, + "Expected 0 or 1, got {d}", + .{builder._unresolved_references.len()}, + ); + }, + } + return Result.new(builder._gpa, builder._semantic, builder._errors); } @@ -109,6 +139,7 @@ pub fn deinit(self: *SemanticBuilder) void { self._scope_stack.deinit(self._gpa); self._symbol_stack.deinit(self._gpa); self._node_stack.deinit(self._gpa); + self._unresolved_references.deinit(self._gpa); } fn parse(self: *SemanticBuilder, source: stringSlice) !Ast { @@ -196,12 +227,12 @@ fn visitNode(self: *SemanticBuilder, node_id: NodeIndex) SemanticError!void { const container = ast.fullContainerDecl(&buf, node_id) orelse unreachable; return self.visitContainer(node_id, container); }, + + // variable/field declarations .container_field, .container_field_align, .container_field_init => { const field = ast.fullContainerField(node_id) orelse unreachable; return self.visitContainerField(node_id, field); }, - .field_access, .unwrap_optional => return self.visit(data[node_id].lhs), - // variable declarations .global_var_decl, .local_var_decl, .simple_var_decl, .aligned_var_decl => { const decl = self.AST().fullVarDecl(node_id) orelse unreachable; return self.visitVarDecl(node_id, decl); @@ -210,6 +241,12 @@ fn visitNode(self: *SemanticBuilder, node_id: NodeIndex) SemanticError!void { const destructure = ast.assignDestructure(node_id); return self.visitAssignDestructure(node_id, destructure); }, + + // variable/field references + .identifier => return self.visitIdentifier(node_id), + .field_access => return self.visitFieldAccess(node_id), + + // initializations .array_init, .array_init_comma, .array_init_dot, @@ -236,6 +273,26 @@ fn visitNode(self: *SemanticBuilder, node_id: NodeIndex) SemanticError!void { const struct_init = ast.fullStructInit(&buf, node_id) orelse unreachable; return self.visitStructInit(node_id, struct_init); }, + // assignment + .assign_mul, + .assign_div, + .assign_mod, + .assign_add, + .assign_sub, + .assign_shl, + .assign_shl_sat, + .assign_shr, + .assign_bit_and, + .assign_bit_xor, + .assign_bit_or, + .assign_mul_wrap, + .assign_add_wrap, + .assign_sub_wrap, + .assign_mul_sat, + .assign_add_sat, + .assign_sub_sat, + .assign, + => return self.visitAssignment(node_id, tag), // function-related nodes // function declarations @@ -321,7 +378,6 @@ fn visitNode(self: *SemanticBuilder, node_id: NodeIndex) SemanticError!void { .test_decl => return self.visit(data[node_id].rhs), // lhs/rhs for these nodes are always undefined - .identifier, .char_literal, .number_literal, .unreachable_literal, @@ -353,6 +409,7 @@ fn visitNode(self: *SemanticBuilder, node_id: NodeIndex) SemanticError!void { // lhs is a node, rhs is a token .grouped_expression, + .unwrap_optional, // lhs is a node, rhs is an index into Slice .slice, .slice_sentinel, @@ -428,6 +485,7 @@ fn visitContainer(self: *SemanticBuilder, _: NodeIndex, container: full.Containe } } +/// ======================= VARIABLE/FIELD DECLARATIONS ======================== /// Visit a container field (e.g. a struct property, enum variant, etc). /// /// ```zig @@ -475,8 +533,36 @@ fn visitVarDecl(self: *SemanticBuilder, node_id: NodeIndex, var_decl: full.VarDe } } -fn visitAssignDestructure(self: *SemanticBuilder, _: NodeIndex, destructure: full.AssignDestructure) SemanticError!void { - self.assertCtx(destructure.ast.variables.len > 0, "Invalid destructuring assignment: no variables are being declared.", .{}); +// ================================ ASSIGNMENT ================================= + +fn visitAssignment(self: *SemanticBuilder, node_id: NodeIndex, tag: Node.Tag) SemanticError!void { + const does_read_lhs = tag != .assign; + const children = self.getNodeData(node_id); + const flags = self._curr_reference_flags; + + { + self._curr_reference_flags.write = true; + self._curr_reference_flags.read = does_read_lhs; + defer self._curr_reference_flags = flags; + try self.visit(children.lhs); + } + { + assert(self._curr_reference_flags.read); + assert(!self._curr_reference_flags.write); + try self.visit(children.rhs); + } +} + +fn visitAssignDestructure( + self: *SemanticBuilder, + _: NodeIndex, + destructure: full.AssignDestructure, +) SemanticError!void { + self.assertCtx( + destructure.ast.variables.len > 0, + "Invalid destructuring assignment: no variables are being declared.", + .{}, + ); const ast = self.AST(); const main_tokens: []TokenIndex = ast.nodes.items(.main_token); const token_tags: []Token.Tag = ast.tokens.items(.tag); @@ -503,6 +589,25 @@ fn visitAssignDestructure(self: *SemanticBuilder, _: NodeIndex, destructure: ful try self.visit(destructure.ast.value_expr); } +// ========================= VARIABLE/FIELD REFERENCES ======================== + +fn visitIdentifier(self: *SemanticBuilder, node_id: NodeIndex) !void { + const ident = self.AST().getNodeSource(node_id); + const symbol = self._semantic.resolveBinding(self.currentScope(), ident); + + _ = try self.recordReference(.{ + .node = node_id, + .symbol = symbol, + .identifier = ident, + }); +} + +fn visitFieldAccess(self: *SemanticBuilder, node_id: NodeIndex) !void { + return self.visit(self.getNodeData(node_id).lhs); +} + +// ============================================================================= + fn visitArrayInit(self: *SemanticBuilder, _: NodeIndex, arr: full.ArrayInit) !void { for (arr.ast.elements) |el| { try self.visit(el); @@ -587,11 +692,14 @@ fn visitCatch(self: *SemanticBuilder, node_id: NodeIndex) !void { } inline fn visitFnProto(self: *SemanticBuilder, _: NodeIndex, fn_proto: full.FnProto) !void { - try self.enterScope(.{}); - defer self.exitScope(); - for (fn_proto.ast.params) |param| { - try self.visit(param); + { + try self.enterScope(.{}); + defer self.exitScope(); + for (fn_proto.ast.params) |param| { + try self.visit(param); + } } + try self.visit(fn_proto.ast.return_type); } inline fn visitFnDecl(self: *SemanticBuilder, node_id: NodeIndex) !void { @@ -665,6 +773,7 @@ fn enterRoot(self: *SemanticBuilder) !void { // SemanticBuilder.init() allocates enough space for 8 scopes. self._scope_stack.appendAssumeCapacity(root_scope_id); + try self._unresolved_references.enter(self._gpa); // push root node onto the stack. It is never popped. // Similar to root scope, the root node is pushed differently than @@ -685,6 +794,8 @@ fn enterRoot(self: *SemanticBuilder) !void { /// /// This function gets erased in ReleaseFast builds. inline fn assertRoot(self: *const SemanticBuilder) void { + if (!util.IS_DEBUG) return // don't run assertions in any kind of release build + self.assertCtx(self._scope_stack.items.len == 1, "assertRoot: scope stack is not at root", .{}); self.assertCtx(self._scope_stack.items[0] == Semantic.ROOT_SCOPE_ID, "assertRoot: scope stack is not at root", .{}); @@ -729,11 +840,14 @@ fn enterScope(self: *SemanticBuilder, flags: Scope.Flags) !void { const merged_flags = flags.merge(self._curr_scope_flags); const scope = try self._semantic.scopes.addScope(self._gpa, parent_id, merged_flags); try self._scope_stack.append(self._gpa, scope); + try self._unresolved_references.enter(self._gpa); } /// Exit the current scope. It is a bug to pop the root scope. inline fn exitScope(self: *SemanticBuilder) void { self.assertCtx(self._scope_stack.items.len > 1, "Invariant violation: cannot pop the root scope", .{}); + self.resolveReferencesInCurrentScope() catch @panic("OOM"); + // self._unresolved_references.exit(self._gpa); _ = self._scope_stack.pop(); } @@ -875,6 +989,157 @@ inline fn declareSymbol( return symbol_id; } +// =========================== Subsection: References ========================== + +const CreateReference = struct { + node: ?NodeIndex = null, + scope: ?Scope.Id = null, + symbol: ?Symbol.Id = null, + flags: Reference.Flags = .{}, + identifier: ?[]const u8 = null, +}; + +fn recordReference(self: *SemanticBuilder, opts: CreateReference) Allocator.Error!Reference.Id { + const node = opts.node orelse self.currentNode(); + const scope = opts.scope orelse self.currentScope(); + const flags = opts.flags.merge(self._curr_reference_flags); + const identifier = opts.identifier orelse brk: { + const ast = self.AST(); + const mains = ast.nodes.items(.main_token); + const token_tags = ast.tokens.items(.tag); + const main_token: TokenIndex = mains[node]; + + if (token_tags[main_token] == .identifier) { + break :brk ast.tokenSlice(main_token); + } + break :brk ast.getNodeSource(node); + }; + + const reference = Reference{ + .symbol = Symbol.Id.Optional.from(opts.symbol), + .identifier = identifier, + .scope = scope, + .flags = flags, + .node = node, + }; + + const ref_id = try self._semantic.symbols.addReference(self._gpa, reference); + if (reference.symbol == .none) { + try self._unresolved_references.append(self._gpa, ref_id); + } + + return ref_id; +} + +fn resolveReferencesInCurrentScope(self: *SemanticBuilder) Allocator.Error!void { + var stacka = std.heap.stackFallback(64, self._gpa); + const stack = stacka.get(); + // + const curr = self._unresolved_references.curr(); + const parent = self._unresolved_references.parent(); + const names = self.symbolTable().symbols.items(.name); + const bindings: []const Symbol.Id = self.scopeTree().getBindings(self.currentScope()); + const ref_names: []const string = self.symbolTable().references.items(.identifier); + const ref_symbols: []Symbol.Id.Optional = self.symbolTable().references.items(.symbol); + + const resolved_map = try stack.alloc(bool, curr.items.len); + var num_resolved: usize = 0; + @memset(resolved_map, false); + defer stack.free(resolved_map); + + for (bindings) |binding| { + const name: string = names[binding.int()]; + for (0..curr.items.len) |i| { + if (resolved_map[i]) continue; + const ref_id: Reference.Id = curr.items[i]; + const ref_name = ref_names[ref_id.int()]; + // we resolved the reference :) + if (mem.eql(u8, name, ref_name)) { + num_resolved += 1; + resolved_map[i] = true; + ref_symbols[ref_id.int()] = binding.into(Symbol.Id.Optional); + } + } + } + + const num_unresolved = curr.items.len - resolved_map.len; + if (num_unresolved > 0) { + if (parent) |p| { + try p.ensureUnusedCapacity(self._gpa, num_unresolved); + for (0..curr.items.len) |i| { + if (resolved_map[i]) continue; + p.appendAssumeCapacity(curr.items[i]); + } + // only delete current frame when we can't move things to the parent. We + // want the last frame to exist so we can move it to the list of + // unresolved references in the symbol table + curr.deinit(self._gpa); + _ = self._unresolved_references.frames.pop(); + } else { + const temp = try self._gpa.dupe(Reference.Id, curr.items); + var i: usize = 0; + var j: usize = 0; + while (i < temp.len) : (i += 1) { + if (!resolved_map[i]) continue; + curr.items[j] = temp[i]; + j += 1; + } + } + } else { + curr.deinit(self._gpa); + _ = self._unresolved_references.frames.pop(); + } +} + +const ReferenceStack = struct { + frames: std.ArrayListUnmanaged(ReferenceIdList) = .{}, + + const ReferenceIdList = std.ArrayListUnmanaged(Reference.Id); + + fn init(alloc: Allocator) Allocator.Error!ReferenceStack { + var self: ReferenceStack = .{}; + try self.frames.ensureTotalCapacity(alloc, 16); + + return self; + } + + /// current frame + pub fn curr(self: *ReferenceStack) *ReferenceIdList { + assert(self.len() > 0); + return &self.frames.items[self.len() - 1]; + } + + /// parent frame. `null` when currently in root scope. + pub fn parent(self: *ReferenceStack) ?*ReferenceIdList { + return if (self.len() <= 1) null else &self.frames.items[self.len() - 2]; + } + + /// current number of frames + inline fn len(self: ReferenceStack) usize { + return self.frames.items.len; + } + + fn enter(self: *ReferenceStack, alloc: Allocator) Allocator.Error!void { + try self.frames.append(alloc, .{}); + } + fn exit(self: *ReferenceStack, alloc: Allocator) void { + var frame = self.frames.pop(); + frame.deinit(alloc); + } + + /// Add an unresolved reference to the current frame + fn append(self: *ReferenceStack, alloc: Allocator, ref: Reference.Id) Allocator.Error!void { + try self.curr().append(alloc, ref); + } + + fn deinit(self: *ReferenceStack, alloc: Allocator) void { + for (0..self.frames.items.len) |i| { + self.frames.items[i].deinit(alloc); + } + self.frames.deinit(alloc); + } +}; + // ========================================================================= // ============================ RANDOM GETTERS ============================= // ========================================================================= @@ -1045,13 +1310,13 @@ fn debugNodeStack(self: *const SemanticBuilder) void { const source = if (id == 0) "" else ast.getNodeSource(id); const loc = ast.tokenLocation(token_offset, main_token); const snippet = - if (source.len > 48) std.mem.concat( + if (source.len > 48) mem.concat( self._gpa, u8, &[_]string{ source[0..32], " ... ", source[(source.len - 16)..source.len] }, ) catch @panic("Out of memory") else source; print(" - [{d}, {d}:{d}] {any} - {s}\n", .{ id, loc.line, loc.column, tag, snippet }); - if (!std.mem.eql(u8, source, snippet)) { + if (!mem.eql(u8, source, snippet)) { self._gpa.free(snippet); } } @@ -1088,8 +1353,10 @@ const Semantic = @import("./Semantic.zig"); const Scope = Semantic.Scope; const Symbol = Semantic.Symbol; const NodeLinks = Semantic.NodeLinks; +const Reference = Semantic.Reference; const std = @import("std"); +const mem = std.mem; const Allocator = std.mem.Allocator; const ArenaAllocator = std.heap.ArenaAllocator; const Type = std.builtin.Type; @@ -1179,3 +1446,53 @@ test "comptime blocks" { try std.testing.expect(block_scope.flags.s_block); try std.testing.expect(block_scope.flags.s_comptime); } + +test "references" { + const t = std.testing; + const alloc = std.testing.allocator; + + const src = + \\fn foo() u32 { + \\ var x: u32 = 1; + \\ const y: u32 = x + 1; + \\ x += y; + \\ return x; + \\} + ; + var builder = SemanticBuilder.init(alloc); + defer builder.deinit(); + var result = try builder.build(src); + defer result.deinit(); + try t.expect(!result.hasErrors()); + const semantic = result.value; + + // FIXME: should be 2 (maybe 3?) but is 4 + try t.expectEqual(4, semantic.scopes.len()); + try t.expectEqual(0, semantic.symbols.unresolved_references.items.len); + + const names = semantic.symbols.symbols.items(.name); + var it = semantic.symbols.iter(); + const x: Symbol.Id = brk: { + while (it.next()) |s| { + if (mem.eql(u8, names[s.int()], "x")) { + break :brk s; + } + } + @panic("Could not find variable `x`."); + }; + + var refs = semantic.symbols.iterReferences(x); + try t.expectEqual(3, refs.len()); + + // const y: u32 = x + 1; + var ref = refs.next().?; + try t.expectEqual(ref.flags, Reference.Flags{ .read = true }); + + // x += y; + ref = refs.next().?; + try t.expectEqual(ref.flags, Reference.Flags{ .read = true, .write = true }); + + // return x; + ref = refs.next().?; + try t.expectEqual(ref.flags, Reference.Flags{ .read = true }); +} diff --git a/src/semantic/Symbol.zig b/src/semantic/Symbol.zig index 27e181c..8a86940 100644 --- a/src/semantic/Symbol.zig +++ b/src/semantic/Symbol.zig @@ -30,12 +30,14 @@ scope: Scope.Id, /// Index of the AST node declaring this symbol. /// /// Usually a `var`/`const` declaration, function statement, etc. -decl: Ast.Node.Index, +decl: Node.Index, visibility: Visibility, flags: Flags, +references: std.ArrayListUnmanaged(Reference.Id) = .{}, + /// Symbols on "instance objects" (e.g. field properties and instance /// methods). /// @@ -113,6 +115,8 @@ pub const SymbolTable = struct { /// /// Do not write to this list directly. symbols: std.MultiArrayList(Symbol) = .{}, + references: std.MultiArrayList(Reference) = .{}, + unresolved_references: std.ArrayListUnmanaged(Reference.Id) = .{}, /// Get a symbol from the table. pub inline fn get(self: *const SymbolTable, id: Symbol.Id) *const Symbol { @@ -122,7 +126,7 @@ pub const SymbolTable = struct { pub fn addSymbol( self: *SymbolTable, alloc: Allocator, - declaration_node: Ast.Node.Index, + declaration_node: Node.Index, name: ?string, debug_name: ?string, scope_id: Scope.Id, @@ -149,6 +153,34 @@ pub const SymbolTable = struct { return id; } + pub fn addReference( + self: *SymbolTable, + alloc: Allocator, + reference: Reference, + ) Allocator.Error!Reference.Id { + const ref_id = Reference.Id.from(self.references.len); + try self.references.append(alloc, reference); + if (reference.symbol.unwrap()) |symbol_id| { + try self.symbols.items(.references)[symbol_id.into(usize)].append(alloc, ref_id); + } + + return ref_id; + } + + pub fn getReference( + self: *const SymbolTable, + reference_id: Reference.Id, + ) Reference { + return self.references.get(reference_id.into(usize)); + } + + pub fn getReferencesMut( + self: *SymbolTable, + symbol_id: Symbol.Id, + ) *std.ArrayListUnmanaged(Reference.Id) { + return &self.symbols.items(.references)[symbol_id.int()]; + } + pub inline fn getMembers(self: *const SymbolTable, container: Symbol.Id) *const SymbolIdList { return &self.symbols.items(.members)[container.int()]; } @@ -177,17 +209,27 @@ pub const SymbolTable = struct { return Iterator{ .table = self }; } + /// Iterate over a symbol's references. + pub inline fn iterReferences(self: *const SymbolTable, id: Symbol.Id) ReferenceIterator { + const refs = self.symbols.items(.references)[id.int()].items; + return ReferenceIterator{ .table = self, .refs = refs }; + } + pub fn deinit(self: *SymbolTable, alloc: Allocator) void { { var i: Id.Repr = 0; const len: Id.Repr = @intCast(self.symbols.len); while (i < len) { - self.getMembersMut(Id.from(i)).deinit(alloc); - self.getExportsMut(Id.from(i)).deinit(alloc); + const id = Id.from(i); + self.getMembersMut(id).deinit(alloc); + self.getExportsMut(id).deinit(alloc); + self.getReferencesMut(id).deinit(alloc); i += 1; } } self.symbols.deinit(alloc); + self.references.deinit(alloc); + self.unresolved_references.deinit(alloc); } }; @@ -205,16 +247,35 @@ pub const Iterator = struct { } }; +pub const ReferenceIterator = struct { + curr: usize = 0, + table: *const SymbolTable, + refs: []Reference.Id, + + pub inline fn len(self: ReferenceIterator) usize { + return self.refs.len; + } + + pub fn next(self: *ReferenceIterator) ?Reference { + if (self.curr >= self.refs.len) return null; + + defer self.curr += 1; + const ref_id = self.refs[self.curr]; + return self.table.getReference(ref_id); + } +}; + const Symbol = @This(); const std = @import("std"); - const Allocator = std.mem.Allocator; -const Ast = std.zig.Ast; -const Scope = @import("Scope.zig"); const Type = std.builtin.Type; const NominalId = @import("id.zig").NominalId; +const Node = std.zig.Ast.Node; +const Scope = @import("Scope.zig"); +const Reference = @import("Reference.zig"); + const assert = std.debug.assert; const string = @import("util").string; diff --git a/src/semantic/id.zig b/src/semantic/id.zig index 58c1347..1d1ee5f 100644 --- a/src/semantic/id.zig +++ b/src/semantic/id.zig @@ -143,6 +143,13 @@ pub fn NominalId(TRepr: type) type { @enumFromInt(@intFromEnum(self)); } + pub inline fn from(id: ?Id) Optional { + return if (id) |i| + @enumFromInt(@intFromEnum(i)) + else + Optional.none; + } + pub inline fn tryFrom(value: anytype) ?Optional { return Id.from(value).optional(); } diff --git a/test/semantic/snapshot_coverage.zig b/test/semantic/snapshot_coverage.zig index ff10dba..4d77286 100644 --- a/test/semantic/snapshot_coverage.zig +++ b/test/semantic/snapshot_coverage.zig @@ -53,6 +53,10 @@ fn runPass(alloc: Allocator, source: *const zlint.Source) anyerror!void { try sem_printer.printSymbolTable(); try printer.pIndent(); + try printer.pPropName("unresolvedReferences"); + try sem_printer.printUnresolvedReferences(); + try printer.pIndent(); + try printer.pPropName("scopes"); try sem_printer.printScopeTree(); printer.pop(); diff --git a/test/snapshots/snapshot-coverage/simple/pass/block.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/block.zig.snap index 1219f1b..77fb500 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/block.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/block.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1,2,3,4,5,6,7,8,9,10,11,12,13,14], "exports": [], @@ -15,6 +18,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -24,6 +30,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(3), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":2,"scope":3,"node":"identifier","identifier":"x","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -33,6 +43,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -42,6 +55,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(7), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":4,"scope":8,"node":"identifier","identifier":"y","flags":{"read":false,"write":true,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -51,6 +68,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -60,6 +80,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(11), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":6,"scope":12,"node":"identifier","identifier":"z","flags":{"read":false,"write":true,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -69,6 +93,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(12), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":7,"scope":12,"node":"identifier","identifier":"a","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -78,6 +106,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -87,6 +118,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(15), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":9,"scope":16,"node":"identifier","identifier":"a","flags":{"read":true,"write":true,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -96,6 +131,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(16), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":10,"scope":16,"node":"identifier","identifier":"b","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -105,6 +144,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(16), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":11,"scope":16,"node":"identifier","identifier":"c","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -114,6 +157,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(16), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":12,"scope":16,"node":"identifier","identifier":"d","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -123,6 +170,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(16), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":13,"scope":16,"node":"identifier","identifier":"e","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -132,11 +183,16 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(16), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":14,"scope":16,"node":"identifier","identifier":"f","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [ diff --git a/test/snapshots/snapshot-coverage/simple/pass/block_comptime.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/block_comptime.zig.snap index 3eb6f7a..65b349f 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/block_comptime.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/block_comptime.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1], "exports": [], @@ -15,6 +18,9 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [2], "exports": [], @@ -24,11 +30,17 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":2,"scope":1,"node":"identifier","identifier":"y","flags":{"read":true,"write":true,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":2,"scope":1,"node":"identifier","identifier":"y","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [ diff --git a/test/snapshots/snapshot-coverage/simple/pass/cond_if.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/cond_if.zig.snap index 4dad069..919fe3b 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/cond_if.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/cond_if.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1,2,3,4,5,6,7], "exports": [], @@ -15,6 +18,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":1,"scope":4,"node":"identifier","identifier":"std","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -24,6 +31,11 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":2,"scope":0,"node":"identifier","identifier":"builtin","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":2,"scope":9,"node":"identifier","identifier":"builtin","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -33,6 +45,9 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -42,6 +57,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -51,6 +69,15 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(3), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":5,"scope":3,"node":"identifier","identifier":"i","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":5,"scope":3,"node":"identifier","identifier":"i","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":5,"scope":5,"node":"identifier","identifier":"i","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":5,"scope":5,"node":"identifier","identifier":"i","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":5,"scope":5,"node":"identifier","identifier":"i","flags":{"read":false,"write":true,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":5,"scope":6,"node":"identifier","identifier":"i","flags":{"read":false,"write":true,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -60,6 +87,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(5), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":6,"scope":5,"node":"identifier","identifier":"pow","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -69,11 +100,15 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [ diff --git a/test/snapshots/snapshot-coverage/simple/pass/enum_members.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/enum_members.zig.snap index 419af42..24d5157 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/enum_members.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/enum_members.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1], "exports": [], @@ -15,6 +18,11 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":1,"scope":2,"node":"identifier","identifier":"Foo","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":1,"scope":4,"node":"identifier","identifier":"Foo","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [2,3,4,5,6], "exports": [], @@ -24,6 +32,9 @@ "declNode": "container_field_init", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":true,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -33,6 +44,9 @@ "declNode": "container_field_init", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":true,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -42,6 +56,9 @@ "declNode": "container_field_init", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":true,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -51,6 +68,9 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -60,11 +80,15 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [ diff --git a/test/snapshots/snapshot-coverage/simple/pass/fibonacci.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/fibonacci.zig.snap index 076dfde..7cdcd93 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/fibonacci.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/fibonacci.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1,2,3,4,5,6,7,8,9], "exports": [], @@ -15,6 +18,13 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":1,"scope":0,"node":"identifier","identifier":"std","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":1,"scope":3,"node":"identifier","identifier":"std","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":1,"scope":3,"node":"identifier","identifier":"std","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":1,"scope":3,"node":"identifier","identifier":"std","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -24,6 +34,12 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":2,"scope":3,"node":"identifier","identifier":"Managed","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":2,"scope":3,"node":"identifier","identifier":"Managed","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":2,"scope":3,"node":"identifier","identifier":"Managed","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -33,6 +49,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -42,6 +61,14 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(3), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":4,"scope":3,"node":"identifier","identifier":"allocator","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":4,"scope":3,"node":"identifier","identifier":"allocator","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":4,"scope":3,"node":"identifier","identifier":"allocator","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":4,"scope":3,"node":"identifier","identifier":"allocator","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":4,"scope":3,"node":"identifier","identifier":"allocator","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -51,6 +78,13 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(3), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":5,"scope":3,"node":"identifier","identifier":"a","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":5,"scope":4,"node":"identifier","identifier":"a","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":5,"scope":4,"node":"identifier","identifier":"a","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":5,"scope":3,"node":"identifier","identifier":"a","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -60,6 +94,13 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(3), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":6,"scope":3,"node":"identifier","identifier":"b","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":6,"scope":4,"node":"identifier","identifier":"b","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":6,"scope":4,"node":"identifier","identifier":"b","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":6,"scope":4,"node":"identifier","identifier":"b","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -69,6 +110,11 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(3), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":7,"scope":3,"node":"identifier","identifier":"i","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":7,"scope":3,"node":"identifier","identifier":"i","flags":{"read":true,"write":true,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -78,6 +124,12 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(3), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":8,"scope":3,"node":"identifier","identifier":"c","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":8,"scope":4,"node":"identifier","identifier":"c","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":8,"scope":4,"node":"identifier","identifier":"c","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -87,11 +139,17 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(3), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":9,"scope":3,"node":"identifier","identifier":"as","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":9,"scope":3,"node":"identifier","identifier":"as","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [ diff --git a/test/snapshots/snapshot-coverage/simple/pass/fn_comptime.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/fn_comptime.zig.snap index 1b9c65c..c51044a 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/fn_comptime.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/fn_comptime.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1,2,3,4,5,6,7,8,9,10], "exports": [], @@ -15,6 +18,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -24,6 +30,9 @@ "declNode": "container_field_init", "scope": semantic.id.NominalId(u32)(4), "flags": {"s_comptime":false,"s_const":false,"s_member":true,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -33,6 +42,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(4), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":3,"scope":5,"node":"identifier","identifier":"Self","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -42,6 +55,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(4), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -51,6 +67,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -60,6 +79,11 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(10), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":6,"scope":10,"node":"identifier","identifier":"l","flags":{"read":true,"write":true,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":6,"scope":10,"node":"identifier","identifier":"l","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -69,6 +93,9 @@ "declNode": "container_field_init", "scope": semantic.id.NominalId(u32)(12), "flags": {"s_comptime":false,"s_const":false,"s_member":true,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -78,6 +105,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -87,6 +117,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(16), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":9,"scope":16,"node":"identifier","identifier":"c","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -96,11 +130,16 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(15), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":10,"scope":15,"node":"identifier","identifier":"a2","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [ diff --git a/test/snapshots/snapshot-coverage/simple/pass/fn_in_fn.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/fn_in_fn.zig.snap index 06257f2..f7aa253 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/fn_in_fn.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/fn_in_fn.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1,2], "exports": [], @@ -15,6 +18,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -24,6 +30,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(3), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":2,"scope":3,"node":"identifier","identifier":"inner","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [3], "exports": [], @@ -33,11 +43,15 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(4), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [ diff --git a/test/snapshots/snapshot-coverage/simple/pass/foo.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/foo.zig.snap index df0749c..c189f82 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/foo.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/foo.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1,2,3,4], "exports": [], @@ -15,6 +18,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":1,"scope":4,"node":"identifier","identifier":"std","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -24,6 +31,9 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -33,6 +43,9 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -42,6 +55,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":4,"scope":2,"node":"identifier","identifier":"Foo","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [5,6,7], "exports": [], @@ -51,6 +68,9 @@ "declNode": "container_field_init", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":true,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -60,6 +80,9 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -69,11 +92,15 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [ diff --git a/test/snapshots/snapshot-coverage/simple/pass/loops_for.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/loops_for.zig.snap index ed94e2a..80f3516 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/loops_for.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/loops_for.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1,2,3,4,5,6], "exports": [], @@ -15,6 +18,11 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":1,"scope":4,"node":"identifier","identifier":"std","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":1,"scope":10,"node":"identifier","identifier":"std","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -24,6 +32,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -33,6 +44,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(3), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":3,"scope":3,"node":"identifier","identifier":"arr","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -42,6 +57,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(4), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":4,"scope":4,"node":"identifier","identifier":"power_of_two","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -51,6 +70,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -60,11 +82,16 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(7), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":6,"scope":7,"node":"identifier","identifier":"mat4x4","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [ diff --git a/test/snapshots/snapshot-coverage/simple/pass/loops_while.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/loops_while.zig.snap index 0e97d43..36f2860 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/loops_while.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/loops_while.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], "exports": [], @@ -15,6 +18,12 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":1,"scope":4,"node":"identifier","identifier":"std","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":1,"scope":8,"node":"identifier","identifier":"std","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":1,"scope":13,"node":"identifier","identifier":"std","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -24,6 +33,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -33,6 +45,13 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(3), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":3,"scope":3,"node":"identifier","identifier":"i","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":3,"scope":4,"node":"identifier","identifier":"i","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":3,"scope":4,"node":"identifier","identifier":"i","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":3,"scope":4,"node":"identifier","identifier":"i","flags":{"read":true,"write":true,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -42,6 +61,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(4), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":4,"scope":4,"node":"identifier","identifier":"power_of_two","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -51,6 +74,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -60,6 +86,12 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(7), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":6,"scope":7,"node":"identifier","identifier":"map","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":6,"scope":7,"node":"identifier","identifier":"map","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":6,"scope":7,"node":"identifier","identifier":"map","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -69,6 +101,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(7), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":7,"scope":7,"node":"identifier","identifier":"iter","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -78,6 +114,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(8), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":8,"scope":8,"node":"identifier","identifier":"k","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -87,6 +127,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(8), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":9,"scope":8,"node":"identifier","identifier":"v","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -96,6 +140,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -105,6 +152,12 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(11), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":11,"scope":11,"node":"identifier","identifier":"x","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":11,"scope":12,"node":"identifier","identifier":"x","flags":{"read":true,"write":true,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":11,"scope":13,"node":"identifier","identifier":"x","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -114,6 +167,12 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(11), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":12,"scope":11,"node":"identifier","identifier":"y","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":12,"scope":12,"node":"identifier","identifier":"y","flags":{"read":true,"write":true,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":12,"scope":13,"node":"identifier","identifier":"y","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -123,6 +182,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(13), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":13,"scope":13,"node":"identifier","identifier":"my_xy","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -132,6 +195,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -141,11 +207,18 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(16), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":15,"scope":16,"node":"identifier","identifier":"i","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":15,"scope":16,"node":"identifier","identifier":"i","flags":{"read":true,"write":true,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":15,"scope":17,"node":"identifier","identifier":"i","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [ diff --git a/test/snapshots/snapshot-coverage/simple/pass/struct_members.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/struct_members.zig.snap index 346dabc..9aa5b53 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/struct_members.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/struct_members.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1], "exports": [], @@ -15,6 +18,9 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [2,3,4], "exports": [], @@ -24,6 +30,9 @@ "declNode": "container_field_init", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":true,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -33,6 +42,9 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -42,11 +54,15 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [ diff --git a/test/snapshots/snapshot-coverage/simple/pass/top_level_struct.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/top_level_struct.zig.snap index 5972cba..f6defc1 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/top_level_struct.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/top_level_struct.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1,2,3,4], "exports": [], @@ -15,6 +18,9 @@ "declNode": "container_field_init", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":true,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -24,6 +30,9 @@ "declNode": "container_field_init", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":true,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -33,6 +42,9 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -42,11 +54,15 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [ diff --git a/test/snapshots/snapshot-coverage/simple/pass/unresolved_import.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/unresolved_import.zig.snap index 063a283..63cfa60 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/unresolved_import.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/unresolved_import.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1], "exports": [], @@ -15,11 +18,15 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [ diff --git a/test/snapshots/snapshot-coverage/simple/pass/writer_interface.zig.snap b/test/snapshots/snapshot-coverage/simple/pass/writer_interface.zig.snap index 8c48617..06a41ef 100644 --- a/test/snapshots/snapshot-coverage/simple/pass/writer_interface.zig.snap +++ b/test/snapshots/snapshot-coverage/simple/pass/writer_interface.zig.snap @@ -6,6 +6,9 @@ "declNode": "root", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":true,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [1], "exports": [], @@ -15,6 +18,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(0), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":1,"scope":9,"node":"identifier","identifier":"Writer","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [2,3,4,5,6,7,10], "exports": [], @@ -24,6 +31,11 @@ "declNode": "container_field_init", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":true,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":2,"scope":4,"node":"identifier","identifier":"ptr","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + {"symbol":2,"scope":4,"node":"identifier","identifier":"ptr","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -33,6 +45,9 @@ "declNode": "container_field_init", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":true,"s_fn":false,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -42,6 +57,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -51,6 +69,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(4), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":5,"scope":4,"node":"identifier","identifier":"T","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -60,6 +82,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(4), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":6,"scope":8,"node":"identifier","identifier":"ptr_info","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -69,6 +95,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(4), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":7,"scope":4,"node":"identifier","identifier":"gen","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [8,9], "exports": [], @@ -78,6 +108,9 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(5), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], @@ -87,6 +120,10 @@ "declNode": "simple_var_decl", "scope": semantic.id.NominalId(u32)(8), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":false,"s_catch_param":false}, + "references": [ + {"symbol":9,"scope":8,"node":"identifier","identifier":"self","flags":{"read":true,"write":false,"call":false,"type":false,"member":false,"_":0}}, + + ], "members": [], "exports": [], @@ -96,11 +133,15 @@ "declNode": "fn_decl", "scope": semantic.id.NominalId(u32)(1), "flags": {"s_comptime":false,"s_const":false,"s_member":false,"s_fn":true,"s_catch_param":false}, + "references": [ + + ], "members": [], "exports": [], }, ], + "unresolvedReferences": [], "scopes": { "id": semantic.id.NominalId(u32)(0), "flags": [