diff --git a/src/DocumentScope.zig b/src/DocumentScope.zig index 88361656f..ea4f3e715 100644 --- a/src/DocumentScope.zig +++ b/src/DocumentScope.zig @@ -665,11 +665,7 @@ noinline fn walkContainerDecl( continue; } - if (token_tags[main_tokens[decl]] != .identifier) { - // TODO this code path should not be reachable - continue; - } - const name = offsets.identifierTokenToNameSlice(tree, main_tokens[decl]); + const name = offsets.identifierTokenToNameSlice(tree, main_tokens[decl]) catch continue; // "TODO this code path should not be reachable" try scope.pushDeclaration(name, .{ .ast_node = decl }, .field); if (is_enum_or_tagged_union) { @@ -698,7 +694,7 @@ noinline fn walkContainerDecl( => { var buffer: [1]Ast.Node.Index = undefined; const name_token = tree.fullFnProto(&buffer, decl).?.name_token orelse continue; - const name = offsets.identifierTokenToNameSlice(tree, name_token); + const name = offsets.identifierTokenToNameSlice(tree, name_token) catch continue; try scope.pushDeclaration(name, .{ .ast_node = decl }, .other); }, .local_var_decl, @@ -709,7 +705,7 @@ noinline fn walkContainerDecl( const name_token = tree.fullVarDecl(decl).?.ast.mut_token + 1; if (name_token >= tree.tokens.len) continue; - const name = offsets.identifierTokenToNameSlice(tree, name_token); + const name = offsets.identifierTokenToNameSlice(tree, name_token) catch continue; try scope.pushDeclaration(name, .{ .ast_node = decl }, .other); }, @@ -752,7 +748,7 @@ noinline fn walkErrorSetNode( switch (token_tags[tok_i]) { .doc_comment, .comma => {}, .identifier => { - const name = offsets.identifierTokenToNameSlice(tree, tok_i); + const name = offsets.identifierTokenToNameSlice(tree, tok_i) catch unreachable; try scope.pushDeclaration(name, .{ .error_token = tok_i }, .other); const gop = try context.doc_scope.error_completions.getOrPut(context.allocator, .{ .label = name, @@ -795,7 +791,7 @@ noinline fn walkFuncNode( while (ast.nextFnParam(&it)) |param| : (param_index += 1) { if (param.name_token) |name_token| { try scope.pushDeclaration( - offsets.identifierTokenToNameSlice(tree, name_token), + offsets.identifierTokenToNameSlice(tree, name_token) catch break, .{ .param_payload = .{ .param_index = param_index, .func = node_idx } }, .other, ); @@ -844,7 +840,7 @@ fn walkBlockNodeKeepOpen( // if labeled block if (token_tags[first_token] == .identifier) { try scope.pushDeclaration( - offsets.identifierTokenToNameSlice(tree, first_token), + offsets.identifierTokenToNameSlice(tree, first_token) catch unreachable, .{ .label_decl = .{ .label = first_token, .block = node_idx } }, .other, ); @@ -862,7 +858,7 @@ fn walkBlockNodeKeepOpen( .simple_var_decl, => { const var_decl = tree.fullVarDecl(idx).?; - const name = offsets.identifierTokenToNameSlice(tree, var_decl.ast.mut_token + 1); + const name = offsets.identifierTokenToNameSlice(tree, var_decl.ast.mut_token + 1) catch continue; try scope.pushDeclaration(name, .{ .ast_node = idx }, .other); }, .assign_destructure => { @@ -871,7 +867,7 @@ fn walkBlockNodeKeepOpen( for (lhs_exprs, 0..) |lhs_node, i| { const var_decl = tree.fullVarDecl(lhs_node) orelse continue; - const name = offsets.identifierTokenToNameSlice(tree, var_decl.ast.mut_token + 1); + const name = offsets.identifierTokenToNameSlice(tree, var_decl.ast.mut_token + 1) catch continue; try scope.pushDeclaration( name, .{ .assign_destructure = .{ .node = idx, .index = @intCast(i) } }, @@ -897,7 +893,7 @@ noinline fn walkIfNode( if (if_node.payload_token) |payload_token| { const name_token = payload_token + @intFromBool(token_tags[payload_token] == .asterisk); - const name = offsets.identifierTokenToNameSlice(tree, name_token); + const name = offsets.identifierTokenToNameSlice(tree, name_token) catch unreachable; const decl: Declaration = if (if_node.error_token != null) .{ .error_union_payload = .{ .name = name_token, .condition = if_node.ast.cond_expr } } @@ -913,7 +909,7 @@ noinline fn walkIfNode( if (if_node.ast.else_expr != 0) { if (if_node.error_token) |error_token| { - const name = offsets.identifierTokenToNameSlice(tree, error_token); + const name = offsets.identifierTokenToNameSlice(tree, error_token) catch unreachable; const else_scope = try walkNodeEnsureScope(context, tree, if_node.ast.else_expr, error_token); try else_scope.pushDeclaration( @@ -944,7 +940,7 @@ noinline fn walkCatchNode( token_tags[catch_token - 1] == .pipe and token_tags[catch_token] == .identifier) { - const name = offsets.identifierTokenToNameSlice(tree, catch_token); + const name = offsets.identifierTokenToNameSlice(tree, catch_token) catch unreachable; const expr_scope = try walkNodeEnsureScope(context, tree, data[node_idx].rhs, catch_token); try expr_scope.pushDeclaration( @@ -978,7 +974,7 @@ noinline fn walkWhileNode( const payload_declaration, const payload_name = if (while_node.payload_token) |payload_token| blk: { const name_token = payload_token + @intFromBool(token_tags[payload_token] == .asterisk); - const name = offsets.identifierTokenToNameSlice(tree, name_token); + const name = offsets.identifierTokenToNameSlice(tree, name_token) catch unreachable; const decl: Declaration = if (while_node.error_token != null) .{ .error_union_payload = .{ .name = name_token, .condition = while_node.ast.cond_expr } } @@ -1031,7 +1027,7 @@ noinline fn walkWhileNode( } if (while_node.error_token) |error_token| { - const name = offsets.identifierTokenToNameSlice(tree, error_token); + const name = offsets.identifierTokenToNameSlice(tree, error_token) catch unreachable; try else_scope.pushDeclaration( name, @@ -1070,16 +1066,15 @@ noinline fn walkForNode( const name_token = capture_token + @intFromBool(capture_is_ref); capture_token = name_token + 2; - if (tree.tokens.items(.tag)[name_token] != .identifier) break; try then_scope.pushDeclaration( - offsets.identifierTokenToNameSlice(tree, name_token), + offsets.identifierTokenToNameSlice(tree, name_token) catch break, .{ .array_payload = .{ .identifier = name_token, .array_expr = input } }, .other, ); } const label_name = if (for_node.label_token) |label_token| - offsets.identifierTokenToNameSlice(context.tree, label_token) + offsets.identifierTokenToNameSlice(context.tree, label_token) catch null else null; @@ -1124,7 +1119,7 @@ noinline fn walkSwitchNode( if (switch_case.payload_token) |payload_token| { const name_token = payload_token + @intFromBool(token_tags[payload_token] == .asterisk); - const name = offsets.identifierTokenToNameSlice(tree, name_token); + const name = offsets.identifierTokenToNameSlice(tree, name_token) catch unreachable; const expr_scope = try walkNodeEnsureScope(context, tree, switch_case.ast.target_expr, name_token); try expr_scope.pushDeclaration( @@ -1148,7 +1143,7 @@ noinline fn walkErrdeferNode( const payload_token = data[node_idx].lhs; if (payload_token != 0) { - const name = offsets.identifierTokenToNameSlice(tree, payload_token); + const name = offsets.identifierTokenToNameSlice(tree, payload_token) catch unreachable; const expr_scope = try walkNodeEnsureScope(context, tree, data[node_idx].rhs, payload_token); try expr_scope.pushDeclaration( diff --git a/src/analysis.zig b/src/analysis.zig index fb24f8fee..30cf6ca25 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -455,7 +455,7 @@ pub fn declNameTokenToSlice(tree: Ast, name_token: Ast.TokenIndex) ?[]const u8 { const name = offsets.tokenToSlice(tree, name_token); return name[1 .. name.len - 1]; }, - .identifier => return offsets.identifierTokenToNameSlice(tree, name_token), + .identifier => return offsets.identifierTokenToNameSlice(tree, name_token) catch return null, else => return null, } } @@ -491,8 +491,7 @@ fn resolveVarDeclAliasInternal(analyser: *Analyser, node_handle: NodeWithHandle, const resolved = switch (node_tags[node_handle.node]) { .identifier => blk: { const name_token = main_tokens[node_handle.node]; - if (token_tags[name_token] != .identifier) return null; - const name = offsets.identifierTokenToNameSlice(tree, name_token); + const name = offsets.identifierTokenToNameSlice(tree, name_token) catch return null; break :blk try analyser.lookupSymbolGlobal( handle, name, @@ -510,7 +509,7 @@ fn resolveVarDeclAliasInternal(analyser: *Analyser, node_handle: NodeWithHandle, else => return null, }; - const symbol_name = offsets.identifierTokenToNameSlice(tree, datas[node_handle.node].rhs); + const symbol_name = offsets.identifierTokenToNameSlice(tree, datas[node_handle.node].rhs) catch return null; break :blk try analyser.lookupSymbolContainer( .{ .node = resolved_node, .handle = resolved.handle }, @@ -1111,7 +1110,6 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) e const main_tokens = tree.nodes.items(.main_token); const node_tags = tree.nodes.items(.tag); const datas = tree.nodes.items(.data); - const token_tags = tree.tokens.items(.tag); const starts = tree.tokens.items(.start); switch (node_tags[node]) { @@ -1142,10 +1140,9 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) e }, .identifier => { const name_token = main_tokens[node]; - if (tree.tokens.items(.tag)[name_token] != .identifier) return null; - const name = offsets.identifierTokenToNameSlice(tree, name_token); + const name = offsets.identifierTokenToNameSlice(tree, name_token) catch return null; - const is_escaped_identifier = tree.source[tree.tokens.items(.start)[name_token]] == '@'; + const is_escaped_identifier = tree.source[starts[name_token]] == '@'; if (!is_escaped_identifier) { if (std.mem.eql(u8, name, "_")) return null; if (try analyser.resolvePrimitive(name)) |primitive| { @@ -1589,10 +1586,17 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) e // HACK: resolve std.ArrayList(T).Slice if (std.mem.endsWith(u8, node_handle.handle.uri, "array_list.zig") and if_node.payload_token != null and - std.mem.eql(u8, offsets.identifierTokenToNameSlice(tree, if_node.payload_token.?), "a") and + std.mem.eql( + u8, + offsets.identifierTokenToNameSlice(tree, if_node.payload_token.?) catch return null, + "a", + ) and node_tags[if_node.ast.cond_expr] == .identifier and - std.mem.eql(u8, offsets.identifierTokenToNameSlice(tree, main_tokens[if_node.ast.cond_expr]), "alignment")) - blk: { + std.mem.eql( + u8, + offsets.identifierTokenToNameSlice(tree, main_tokens[if_node.ast.cond_expr]) catch return null, + "alignment", + )) blk: { return (try analyser.resolveTypeOfNodeInternal(.{ .handle = handle, .node = if_node.ast.then_expr })) orelse break :blk; } @@ -1680,9 +1684,7 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) e .block_two_semicolon, => { const first_token = tree.firstToken(node); - if (token_tags[first_token] != .identifier) return null; - - const block_label = offsets.identifierTokenToNameSlice(tree, first_token); + const block_label = offsets.identifierTokenToNameSlice(tree, first_token) catch return null; // TODO: peer type resolution based on all `break` statements var context = FindBreaks{ @@ -2415,7 +2417,7 @@ pub fn getFieldAccessType( .eof => return current_type, .identifier => { const ct_handle = if (current_type) |c| c.handle else handle; - const symbol_name = offsets.identifierIndexToNameSlice(tokenizer.buffer, tok.loc.start); + const symbol_name = offsets.identifierIndexToNameSlice(tokenizer.buffer, tok.loc.start) catch return null; if (try analyser.lookupSymbolGlobal( ct_handle, symbol_name, @@ -2446,7 +2448,7 @@ pub fn getFieldAccessType( else return null; - const symbol = offsets.identifierIndexToNameSlice(tokenizer.buffer, after_period.loc.start); + const symbol = offsets.identifierIndexToNameSlice(tokenizer.buffer, after_period.loc.start) catch return null; const current_type_nodes = try deref_type.getAllTypesWithHandles(analyser.arena.allocator()); // TODO: Return all options instead of first valid one @@ -2584,7 +2586,7 @@ pub fn nodeToString(tree: Ast, node: Ast.Node.Index) ?[]const u8 { return if (field.tuple_like) null else tree.tokenSlice(field.main_token); }, .error_value => tree.tokenSlice(data[node].rhs), - .identifier => offsets.identifierTokenToNameSlice(tree, main_token), + .identifier => offsets.identifierTokenToNameSlice(tree, main_token) catch null, .fn_proto, .fn_proto_multi, .fn_proto_one, @@ -3215,10 +3217,9 @@ pub const DeclWithHandle = struct { } return try analyser.resolveTypeOfNodeInternal(.{ .node = param.type_expr, .handle = self.handle }); } else if (node_tags[param.type_expr] == .identifier) { - if (tree.tokens.items(.tag)[main_tokens[param.type_expr]] != .identifier) return null; - const param_type_name = offsets.identifierTokenToNameSlice(tree, main_tokens[param.type_expr]); + const param_type_name = offsets.identifierTokenToNameSlice(tree, main_tokens[param.type_expr]) catch return null; if (param.name_token) |name_tok| { - const name = offsets.identifierTokenToNameSlice(tree, name_tok); + const name = offsets.identifierTokenToNameSlice(tree, name_tok) catch return null; if (std.mem.eql(u8, param_type_name, name)) return null; } @@ -4448,13 +4449,13 @@ fn addReferencedTypes( .enum_literal => return "@TypeOf(.enum_literal)", .error_value => { - const identifier = offsets.identifierTokenToNameSlice(tree, datas[p].rhs); + const identifier = offsets.identifierTokenToNameSlice(tree, datas[p].rhs) catch return null; return try std.fmt.allocPrint(allocator, "error{{{}}}", .{std.zig.fmtId(identifier)}); }, .identifier => { const name_token = main_tokens[p]; - const name = offsets.identifierTokenToNameSlice(tree, name_token); + const name = offsets.identifierTokenToNameSlice(tree, name_token) catch return null; const is_escaped_identifier = tree.source[tree.tokens.items(.start)[name_token]] == '@'; if (is_escaped_identifier) return null; const primitive = try analyser.resolvePrimitive(name) orelse return null; diff --git a/src/features/inlay_hints.zig b/src/features/inlay_hints.zig index 0debfd6d9..9846b3cf3 100644 --- a/src/features/inlay_hints.zig +++ b/src/features/inlay_hints.zig @@ -337,7 +337,7 @@ fn writeCallNodeHint(builder: *Builder, call: Ast.full.Call) !void { switch (node_tags[call.ast.fn_expr]) { .identifier => { const name_token = main_tokens[call.ast.fn_expr]; - const name = offsets.identifierTokenToNameSlice(tree, name_token); + const name = offsets.identifierTokenToNameSlice(tree, name_token) catch return; const source_index = offsets.tokenToIndex(tree, name_token); if (try builder.analyser.lookupSymbolGlobal(handle, name, source_index)) |decl_handle| { @@ -359,7 +359,7 @@ fn writeCallNodeHint(builder: *Builder, call: Ast.full.Call) !void { .end = rhs_loc.end, })) |type_handle| { const container_handle = try builder.analyser.resolveDerefType(type_handle) orelse type_handle; - const symbol = offsets.identifierTokenToNameSlice(tree, rhsToken); + const symbol = offsets.identifierTokenToNameSlice(tree, rhsToken) catch return; if (try container_handle.lookupSymbol(builder.analyser, symbol)) |decl_handle| { try writeCallHint(builder, call, decl_handle); } diff --git a/src/features/semantic_tokens.zig b/src/features/semantic_tokens.zig index 0387a5ef0..5c21be80c 100644 --- a/src/features/semantic_tokens.zig +++ b/src/features/semantic_tokens.zig @@ -995,7 +995,7 @@ fn writeIdentifier(builder: *Builder, name_token: Ast.Node.Index) error{OutOfMem const handle = builder.handle; const tree = handle.tree; - const name = offsets.identifierTokenToNameSlice(tree, name_token); + const name = offsets.identifierTokenToNameSlice(tree, name_token) catch return; const is_escaped_identifier = tree.source[tree.tokens.items(.start)[name_token]] == '@'; if (!is_escaped_identifier) { diff --git a/src/offsets.zig b/src/offsets.zig index bad8a9bbd..76fe3f2eb 100644 --- a/src/offsets.zig +++ b/src/offsets.zig @@ -127,11 +127,11 @@ pub fn sourceIndexToTokenIndex(tree: Ast, source_index: usize) Ast.TokenIndex { return @intCast(upper_index); } -fn identifierIndexToLoc(tree: Ast, source_index: usize) Loc { +fn identifierIndexToLoc(tree: Ast, source_index: usize) error{NotAnIdentifier}!Loc { var index: usize = source_index; if (tree.source[index] == '@') { index += 1; - std.debug.assert(tree.source[index] == '\"'); + if (tree.source[index] != '\"') return error.NotAnIdentifier; index += 1; while (true) : (index += 1) { if (tree.source[index] == '\"') { @@ -150,9 +150,9 @@ fn identifierIndexToLoc(tree: Ast, source_index: usize) Loc { return .{ .start = source_index, .end = index }; } -pub fn identifierIndexToNameLoc(text: [:0]const u8, source_index: usize) Loc { +pub fn identifierIndexToNameLoc(text: [:0]const u8, source_index: usize) error{NotAnIdentifier}!Loc { if (text[source_index] == '@') { - std.debug.assert(text[source_index + 1] == '\"'); + if (text[source_index + 1] != '\"') return error.NotAnIdentifier; const start_index = source_index + 2; var index: usize = start_index; while (true) : (index += 1) { @@ -173,17 +173,17 @@ pub fn identifierIndexToNameLoc(text: [:0]const u8, source_index: usize) Loc { } } -pub fn identifierIndexToNameSlice(text: [:0]const u8, source_index: usize) []const u8 { - return locToSlice(text, identifierIndexToNameLoc(text, source_index)); +pub fn identifierIndexToNameSlice(text: [:0]const u8, source_index: usize) error{NotAnIdentifier}![]const u8 { + return locToSlice(text, try identifierIndexToNameLoc(text, source_index)); } -pub fn identifierTokenToNameLoc(tree: Ast, identifier_token: Ast.TokenIndex) Loc { - std.debug.assert(tree.tokens.items(.tag)[identifier_token] == .identifier); +pub fn identifierTokenToNameLoc(tree: Ast, identifier_token: Ast.TokenIndex) error{NotAnIdentifier}!Loc { + if (tree.tokens.items(.tag)[identifier_token] != .identifier) return error.NotAnIdentifier; return identifierIndexToNameLoc(tree.source, tree.tokens.items(.start)[identifier_token]); } -pub fn identifierTokenToNameSlice(tree: Ast, identifier_token: Ast.TokenIndex) []const u8 { - return locToSlice(tree.source, identifierTokenToNameLoc(tree, identifier_token)); +pub fn identifierTokenToNameSlice(tree: Ast, identifier_token: Ast.TokenIndex) error{NotAnIdentifier}![]const u8 { + return locToSlice(tree.source, try identifierTokenToNameLoc(tree, identifier_token)); } pub fn tokenToIndex(tree: Ast, token_index: Ast.TokenIndex) usize { @@ -203,7 +203,7 @@ pub fn tokenToLoc(tree: Ast, token_index: Ast.TokenIndex) Loc { // Many tokens can be determined entirely by their tag. if (tag == .identifier) { // fast path for identifiers - return identifierIndexToLoc(tree, start); + return identifierIndexToLoc(tree, start) catch unreachable; } else if (tag.lexeme()) |lexeme| { return .{ .start = start, diff --git a/tests/utility/offsets.zig b/tests/utility/offsets.zig index f3c84587a..9317ffae2 100644 --- a/tests/utility/offsets.zig +++ b/tests/utility/offsets.zig @@ -65,17 +65,17 @@ test "offsets - tokenIndexToLoc" { } test "offsets - identifierIndexToNameLoc" { - try std.testing.expectEqualStrings("", offsets.identifierIndexToNameSlice("", 0)); - try std.testing.expectEqualStrings("", offsets.identifierIndexToNameSlice(" ", 0)); - try std.testing.expectEqualStrings("", offsets.identifierIndexToNameSlice(" world", 0)); + try std.testing.expectEqualStrings("", try offsets.identifierIndexToNameSlice("", 0)); + try std.testing.expectEqualStrings("", try offsets.identifierIndexToNameSlice(" ", 0)); + try std.testing.expectEqualStrings("", try offsets.identifierIndexToNameSlice(" world", 0)); - try std.testing.expectEqualStrings("hello", offsets.identifierIndexToNameSlice("hello", 0)); - try std.testing.expectEqualStrings("hello", offsets.identifierIndexToNameSlice("hello world", 0)); - try std.testing.expectEqualStrings("world", offsets.identifierIndexToNameSlice("hello world", 6)); + try std.testing.expectEqualStrings("hello", try offsets.identifierIndexToNameSlice("hello", 0)); + try std.testing.expectEqualStrings("hello", try offsets.identifierIndexToNameSlice("hello world", 0)); + try std.testing.expectEqualStrings("world", try offsets.identifierIndexToNameSlice("hello world", 6)); - try std.testing.expectEqualStrings("hello", offsets.identifierIndexToNameSlice("@\"hello\"", 0)); - try std.testing.expectEqualStrings("hello", offsets.identifierIndexToNameSlice("@\"hello\" world", 0)); - try std.testing.expectEqualStrings("world", offsets.identifierIndexToNameSlice("@\"hello\" @\"world\"", 9)); + try std.testing.expectEqualStrings("hello", try offsets.identifierIndexToNameSlice("@\"hello\"", 0)); + try std.testing.expectEqualStrings("hello", try offsets.identifierIndexToNameSlice("@\"hello\" world", 0)); + try std.testing.expectEqualStrings("world", try offsets.identifierIndexToNameSlice("@\"hello\" @\"world\"", 9)); } test "offsets - lineLocAtIndex" {