From bebd710f3ee23230ab823a9515016d7fef8dc7e9 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 18 Sep 2025 23:06:11 +0200 Subject: [PATCH 1/2] zig fmt: preserve formatting for function parameters with doc comments Previously, zig fmt would collapse function declarations with doc comments onto a single line, creating invalid syntax like: ```zig fn foo(/// comment _: void) void {} ``` Now we check for doc comments between parentheses and prevent the single-line formatting when doc comments are present, ensuring proper line separation and adding trailing comma when needed. Fixes #18088 --- lib/std/zig/Ast/Render.zig | 13 ++++++++++++- lib/std/zig/parser_test.zig | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/std/zig/Ast/Render.zig b/lib/std/zig/Ast/Render.zig index b3ba5ffad15f..9205fdab41af 100644 --- a/lib/std/zig/Ast/Render.zig +++ b/lib/std/zig/Ast/Render.zig @@ -1718,7 +1718,18 @@ fn renderFnProto(r: *Render, fn_proto: Ast.full.FnProto, space: Space) Error!voi // The params list is a sparse set that does *not* include anytype or ... parameters. const trailing_comma = tree.tokenTag(rparen - 1) == .comma; - if (!trailing_comma and !hasComment(tree, lparen, rparen)) { + + // Check if there are any doc comment tokens between lparen and rparen + var has_doc_comment = false; + for (lparen..rparen) |i| { + const token: Ast.TokenIndex = @intCast(i); + if (tree.tokenTag(token) == .doc_comment) { + has_doc_comment = true; + break; + } + } + + if (!trailing_comma and !hasComment(tree, lparen, rparen) and !has_doc_comment) { // Render all on one line, no trailing comma. try renderToken(r, lparen, .none); // ( diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index fce5cbd209e9..0422556c2413 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -1342,6 +1342,24 @@ test "zig fmt: doc comments on param decl" { ); } +test "zig fmt: doc comments on param decl without trailing comma" { + try testTransform( + \\fn f( + \\ /// comment + \\ x: u32, + \\ y: u32 + \\) void {} + \\ + , + \\fn f( + \\ /// comment + \\ x: u32, + \\ y: u32, + \\) void {} + \\ + ); +} + test "zig fmt: aligned struct field" { try testCanonical( \\pub const S = struct { From 6c8f9e49be7039bb220e941eb263dc0a81f561fd Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 18 Sep 2025 23:00:20 +0200 Subject: [PATCH 2/2] Format --- lib/std/Build/WebServer.zig | 25 ++++++++++++++----------- lib/std/time/epoch.zig | 21 +++++++++++++-------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/lib/std/Build/WebServer.zig b/lib/std/Build/WebServer.zig index 1b3e3bfe82cc..0946453c1ef7 100644 --- a/lib/std/Build/WebServer.zig +++ b/lib/std/Build/WebServer.zig @@ -672,20 +672,23 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim return base_path.join(arena, bin_name); } -pub fn updateTimeReportCompile(ws: *WebServer, opts: struct { - compile: *Build.Step.Compile, +pub fn updateTimeReportCompile( + ws: *WebServer, + opts: struct { + compile: *Build.Step.Compile, - use_llvm: bool, - stats: abi.time_report.CompileResult.Stats, - ns_total: u64, + use_llvm: bool, + stats: abi.time_report.CompileResult.Stats, + ns_total: u64, - llvm_pass_timings_len: u32, - files_len: u32, - decls_len: u32, + llvm_pass_timings_len: u32, + files_len: u32, + decls_len: u32, - /// The trailing data of `abi.time_report.CompileResult`, except the step name. - trailing: []const u8, -}) void { + /// The trailing data of `abi.time_report.CompileResult`, except the step name. + trailing: []const u8, + }, +) void { const gpa = ws.gpa; const step_idx: u32 = for (ws.all_steps, 0..) |s, i| { diff --git a/lib/std/time/epoch.zig b/lib/std/time/epoch.zig index fa7499aec7ec..e9c2331ab32d 100644 --- a/lib/std/time/epoch.zig +++ b/lib/std/time/epoch.zig @@ -182,14 +182,19 @@ pub const EpochSeconds = struct { } }; -fn testEpoch(secs: u64, expected_year_day: YearAndDay, expected_month_day: MonthAndDay, expected_day_seconds: struct { - /// 0 to 23 - hours_into_day: u5, - /// 0 to 59 - minutes_into_hour: u6, - /// 0 to 59 - seconds_into_minute: u6, -}) !void { +fn testEpoch( + secs: u64, + expected_year_day: YearAndDay, + expected_month_day: MonthAndDay, + expected_day_seconds: struct { + /// 0 to 23 + hours_into_day: u5, + /// 0 to 59 + minutes_into_hour: u6, + /// 0 to 59 + seconds_into_minute: u6, + }, +) !void { const epoch_seconds = EpochSeconds{ .secs = secs }; const epoch_day = epoch_seconds.getEpochDay(); const day_seconds = epoch_seconds.getDaySeconds();