authorgravatar for johnnymarler@gmail.comJonathan Marler <johnnymarler@gmail.com> 2021-01-03 02:20:37-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-09 22:25:52-08:00
log1480c428065c01c6feff22ce84021c2e0e30aa9b
treeb54dc7156319d92d5947188b4684b4faae1ee8eb
parent6a5a6386c60143258fc9970f52e26e3a974b52b5

require specifier for arrayish types


8 files changed, 71 insertions(+), 46 deletions(-)

lib/std/build.zig+1-1
......@@ -739,7 +739,7 @@ pub const Builder = struct {
739739 return args.default_target;
740740 },
741741 else => |e| {
742 warn("Unable to parse target '{}': {s}\n\n", .{ triple, @errorName(e) });
742 warn("Unable to parse target '{s}': {s}\n\n", .{ triple, @errorName(e) });
743743 self.markInvalidUserInput();
744744 return args.default_target;
745745 },
lib/std/fmt.zig+55-30
......@@ -69,6 +69,7 @@ pub const FormatOptions = struct {
6969/// - `c`: output integer as an ASCII character. Integer type must have 8 bits at max.
7070/// - `u`: output integer as an UTF-8 sequence. Integer type must have 21 bits at max.
7171/// - `*`: output the address of the value instead of the value itself.
72/// - `any`: output a value of any type using its default format
7273///
7374/// If a formatted user type contains a function of the type
7475/// ```
......@@ -387,17 +388,32 @@ pub fn formatAddress(value: anytype, options: FormatOptions, writer: anytype) @T
387388 return;
388389 }
389390 },
390 .Array => |info| {
391 try writer.writeAll(@typeName(info.child) ++ "@");
392 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer);
393 return;
394 },
395391 else => {},
396392 }
397393
398394 @compileError("Cannot format non-pointer type " ++ @typeName(T) ++ " with * specifier");
399395}
400396
397// This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948
398const ANY = "any";
399
400fn defaultSpec(comptime T: type) [:0]const u8 {
401 switch (@typeInfo(T)) {
402 .Array => |_| return ANY,
403 .Pointer => |ptr_info| switch (ptr_info.size) {
404 .One => switch (@typeInfo(ptr_info.child)) {
405 .Array => |_| return "*",
406 else => {},
407 },
408 .Many, .C => return "*",
409 .Slice => return ANY,
410 },
411 .Optional => |info| return defaultSpec(info.child),
412 else => {},
413 }
414 return "";
415}
416
401417pub fn formatType(
402418 value: anytype,
403419 comptime fmt: []const u8,
......@@ -405,18 +421,19 @@ pub fn formatType(
405421 writer: anytype,
406422 max_depth: usize,
407423) @TypeOf(writer).Error!void {
408 if (comptime std.mem.eql(u8, fmt, "*")) {
424 const actual_fmt = comptime if (std.mem.eql(u8, fmt, ANY)) defaultSpec(@TypeOf(value)) else fmt;
425 if (comptime std.mem.eql(u8, actual_fmt, "*")) {
409426 return formatAddress(value, options, writer);
410427 }
411428
412429 const T = @TypeOf(value);
413430 if (comptime std.meta.trait.hasFn("format")(T)) {
414 return try value.format(fmt, options, writer);
431 return try value.format(actual_fmt, options, writer);
415432 }
416433
417434 switch (@typeInfo(T)) {
418435 .ComptimeInt, .Int, .ComptimeFloat, .Float => {
419 return formatValue(value, fmt, options, writer);
436 return formatValue(value, actual_fmt, options, writer);
420437 },
421438 .Void => {
422439 return formatBuf("void", options, writer);
......@@ -426,16 +443,16 @@ pub fn formatType(
426443 },
427444 .Optional => {
428445 if (value) |payload| {
429 return formatType(payload, fmt, options, writer, max_depth);
446 return formatType(payload, actual_fmt, options, writer, max_depth);
430447 } else {
431448 return formatBuf("null", options, writer);
432449 }
433450 },
434451 .ErrorUnion => {
435452 if (value) |payload| {
436 return formatType(payload, fmt, options, writer, max_depth);
453 return formatType(payload, actual_fmt, options, writer, max_depth);
437454 } else |err| {
438 return formatType(err, fmt, options, writer, max_depth);
455 return formatType(err, actual_fmt, options, writer, max_depth);
439456 }
440457 },
441458 .ErrorSet => {
......@@ -461,7 +478,7 @@ pub fn formatType(
461478 }
462479
463480 try writer.writeAll("(");
464 try formatType(@enumToInt(value), fmt, options, writer, max_depth);
481 try formatType(@enumToInt(value), actual_fmt, options, writer, max_depth);
465482 try writer.writeAll(")");
466483 },
467484 .Union => |info| {
......@@ -475,7 +492,7 @@ pub fn formatType(
475492 try writer.writeAll(" = ");
476493 inline for (info.fields) |u_field| {
477494 if (value == @field(UnionTagType, u_field.name)) {
478 try formatType(@field(value, u_field.name), fmt, options, writer, max_depth - 1);
495 try formatType(@field(value, u_field.name), ANY, options, writer, max_depth - 1);
479496 }
480497 }
481498 try writer.writeAll(" }");
......@@ -497,48 +514,54 @@ pub fn formatType(
497514 }
498515 try writer.writeAll(f.name);
499516 try writer.writeAll(" = ");
500 try formatType(@field(value, f.name), fmt, options, writer, max_depth - 1);
517 try formatType(@field(value, f.name), ANY, options, writer, max_depth - 1);
501518 }
502519 try writer.writeAll(" }");
503520 },
504521 .Pointer => |ptr_info| switch (ptr_info.size) {
505522 .One => switch (@typeInfo(ptr_info.child)) {
506523 .Array => |info| {
524 if (actual_fmt.len == 0)
525 @compileError("cannot format array ref without a specifier (i.e. {s} or {*})");
507526 if (info.child == u8) {
508 if (fmt.len > 0 and comptime mem.indexOfScalar(u8, "sxXeEzZ", fmt[0]) != null) {
509 return formatText(value, fmt, options, writer);
527 if (comptime mem.indexOfScalar(u8, "sxXeEzZ", actual_fmt[0]) != null) {
528 return formatText(value, actual_fmt, options, writer);
510529 }
511530 }
512 return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value) });
531 @compileError("Unknown format string: '" ++ actual_fmt ++ "'");
513532 },
514533 .Enum, .Union, .Struct => {
515 return formatType(value.*, fmt, options, writer, max_depth);
534 return formatType(value.*, actual_fmt, options, writer, max_depth);
516535 },
517536 else => return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value) }),
518537 },
519538 .Many, .C => {
539 if (actual_fmt.len == 0)
540 @compileError("cannot format pointer without a specifier (i.e. {s} or {*})");
520541 if (ptr_info.sentinel) |sentinel| {
521 return formatType(mem.span(value), fmt, options, writer, max_depth);
542 return formatType(mem.span(value), actual_fmt, options, writer, max_depth);
522543 }
523544 if (ptr_info.child == u8) {
524 if (fmt.len > 0 and comptime mem.indexOfScalar(u8, "sxXeEzZ", fmt[0]) != null) {
525 return formatText(mem.span(value), fmt, options, writer);
545 if (comptime mem.indexOfScalar(u8, "sxXeEzZ", actual_fmt[0]) != null) {
546 return formatText(mem.span(value), actual_fmt, options, writer);
526547 }
527548 }
528 return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value) });
549 @compileError("Unknown format string: '" ++ actual_fmt ++ "'");
529550 },
530551 .Slice => {
552 if (actual_fmt.len == 0)
553 @compileError("cannot format slice without a specifier (i.e. {s} or {any})");
531554 if (max_depth == 0) {
532555 return writer.writeAll("{ ... }");
533556 }
534557 if (ptr_info.child == u8) {
535 if (fmt.len > 0 and comptime mem.indexOfScalar(u8, "sxXeEzZ", fmt[0]) != null) {
536 return formatText(value, fmt, options, writer);
558 if (comptime mem.indexOfScalar(u8, "sxXeEzZ", actual_fmt[0]) != null) {
559 return formatText(value, actual_fmt, options, writer);
537560 }
538561 }
539562 try writer.writeAll("{ ");
540563 for (value) |elem, i| {
541 try formatType(elem, fmt, options, writer, max_depth - 1);
564 try formatType(elem, actual_fmt, options, writer, max_depth - 1);
542565 if (i != value.len - 1) {
543566 try writer.writeAll(", ");
544567 }
......@@ -547,17 +570,19 @@ pub fn formatType(
547570 },
548571 },
549572 .Array => |info| {
573 if (actual_fmt.len == 0)
574 @compileError("cannot format array without a specifier (i.e. {s} or {any})");
550575 if (max_depth == 0) {
551576 return writer.writeAll("{ ... }");
552577 }
553578 if (info.child == u8) {
554 if (fmt.len > 0 and comptime mem.indexOfScalar(u8, "sxXeEzZ", fmt[0]) != null) {
555 return formatText(&value, fmt, options, writer);
579 if (comptime mem.indexOfScalar(u8, "sxXeEzZ", actual_fmt[0]) != null) {
580 return formatText(&value, actual_fmt, options, writer);
556581 }
557582 }
558583 try writer.writeAll("{ ");
559584 for (value) |elem, i| {
560 try formatType(elem, fmt, options, writer, max_depth - 1);
585 try formatType(elem, actual_fmt, options, writer, max_depth - 1);
561586 if (i < value.len - 1) {
562587 try writer.writeAll(", ");
563588 }
......@@ -568,7 +593,7 @@ pub fn formatType(
568593 try writer.writeAll("{ ");
569594 var i: usize = 0;
570595 while (i < info.len) : (i += 1) {
571 try formatValue(value[i], fmt, options, writer);
596 try formatValue(value[i], actual_fmt, options, writer);
572597 if (i < info.len - 1) {
573598 try writer.writeAll(", ");
574599 }
......@@ -1668,7 +1693,7 @@ test "slice" {
16681693 {
16691694 var int_slice = [_]u32{ 1, 4096, 391891, 1111111111 };
16701695 var runtime_zero: usize = 0;
1671 try expectFmt("int: { 1, 4096, 391891, 1111111111 }", "int: {}", .{int_slice[runtime_zero..]});
1696 try expectFmt("int: { 1, 4096, 391891, 1111111111 }", "int: {any}", .{int_slice[runtime_zero..]});
16721697 try expectFmt("int: { 1, 4096, 391891, 1111111111 }", "int: {d}", .{int_slice[runtime_zero..]});
16731698 try expectFmt("int: { 1, 1000, 5fad3, 423a35c7 }", "int: {x}", .{int_slice[runtime_zero..]});
16741699 try expectFmt("int: { 00001, 01000, 5fad3, 423a35c7 }", "int: {x:0>5}", .{int_slice[runtime_zero..]});
lib/std/testing.zig+7-7
......@@ -29,7 +29,7 @@ pub var zig_exe_path: []const u8 = undefined;
2929/// and then aborts when actual_error_union is not expected_error.
3030pub fn expectError(expected_error: anyerror, actual_error_union: anytype) void {
3131 if (actual_error_union) |actual_payload| {
32 std.debug.panic("expected error.{s}, found {}", .{ @errorName(expected_error), actual_payload });
32 std.debug.panic("expected error.{s}, found {any}", .{ @errorName(expected_error), actual_payload });
3333 } else |actual_error| {
3434 if (expected_error != actual_error) {
3535 std.debug.panic("expected error.{s}, found error.{s}", .{
......@@ -88,7 +88,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) void {
8888 },
8989 .Slice => {
9090 if (actual.ptr != expected.ptr) {
91 std.debug.panic("expected slice ptr {}, found {}", .{ expected.ptr, actual.ptr });
91 std.debug.panic("expected slice ptr {*}, found {*}", .{ expected.ptr, actual.ptr });
9292 }
9393 if (actual.len != expected.len) {
9494 std.debug.panic("expected slice len {}, found {}", .{ expected.len, actual.len });
......@@ -145,11 +145,11 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) void {
145145 if (actual) |actual_payload| {
146146 expectEqual(expected_payload, actual_payload);
147147 } else {
148 std.debug.panic("expected {}, found null", .{expected_payload});
148 std.debug.panic("expected {any}, found null", .{expected_payload});
149149 }
150150 } else {
151151 if (actual) |actual_payload| {
152 std.debug.panic("expected null, found {}", .{actual_payload});
152 std.debug.panic("expected null, found {any}", .{actual_payload});
153153 }
154154 }
155155 },
......@@ -159,11 +159,11 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) void {
159159 if (actual) |actual_payload| {
160160 expectEqual(expected_payload, actual_payload);
161161 } else |actual_err| {
162 std.debug.panic("expected {}, found {}", .{ expected_payload, actual_err });
162 std.debug.panic("expected {any}, found {}", .{ expected_payload, actual_err });
163163 }
164164 } else |expected_err| {
165165 if (actual) |actual_payload| {
166 std.debug.panic("expected {}, found {}", .{ expected_err, actual_payload });
166 std.debug.panic("expected {}, found {any}", .{ expected_err, actual_payload });
167167 } else |actual_err| {
168168 expectEqual(expected_err, actual_err);
169169 }
......@@ -279,7 +279,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
279279 var i: usize = 0;
280280 while (i < expected.len) : (i += 1) {
281281 if (!std.meta.eql(expected[i], actual[i])) {
282 std.debug.panic("index {} incorrect. expected {}, found {}", .{ i, expected[i], actual[i] });
282 std.debug.panic("index {} incorrect. expected {any}, found {any}", .{ i, expected[i], actual[i] });
283283 }
284284 }
285285}
src/Module.zig+1-1
......@@ -2400,7 +2400,7 @@ fn getAnonTypeName(self: *Module, scope: *Scope, base_token: std.zig.ast.TokenIn
24002400 else => unreachable,
24012401 };
24022402 const loc = tree.tokenLocationLoc(0, tree.token_locs[base_token]);
2403 return std.fmt.allocPrint(self.gpa, "{}:{}:{}", .{ base_name, loc.line, loc.column });
2403 return std.fmt.allocPrint(self.gpa, "{s}:{}:{}", .{ base_name, loc.line, loc.column });
24042404}
24052405
24062406fn getNextAnonNameIndex(self: *Module) usize {
src/codegen.zig+1-1
......@@ -2223,7 +2223,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
22232223 writeInt(u32, try self.code.addManyAsArray(4), Instruction.cmp(.al, reg, op).toU32());
22242224 break :blk .ne;
22252225 },
2226 else => return self.fail(inst.base.src, "TODO implement condbr {} when condition is {}", .{ self.target.cpu.arch, @tagName(cond) }),
2226 else => return self.fail(inst.base.src, "TODO implement condbr {} when condition is {s}", .{ self.target.cpu.arch, @tagName(cond) }),
22272227 };
22282228
22292229 const reloc = Reloc{
src/zir_sema.zig+1-1
......@@ -1832,7 +1832,7 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In
18321832 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
18331833
18341834 if (!is_int) {
1835 return mod.fail(scope, inst.base.src, "invalid operands to binary bitwise expression: '{}' and '{}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) });
1835 return mod.fail(scope, inst.base.src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) });
18361836 }
18371837
18381838 if (casted_lhs.value()) |lhs_val| {
test/cli.zig+4-4
......@@ -51,9 +51,9 @@ fn unwrapArg(arg: UnwrapArgError![]u8) UnwrapArgError![]u8 {
5151}
5252
5353fn printCmd(cwd: []const u8, argv: []const []const u8) void {
54 std.debug.warn("cd {} && ", .{cwd});
54 std.debug.warn("cd {s} && ", .{cwd});
5555 for (argv) |arg| {
56 std.debug.warn("{} ", .{arg});
56 std.debug.warn("{s} ", .{arg});
5757 }
5858 std.debug.warn("\n", .{});
5959}
......@@ -75,14 +75,14 @@ fn exec(cwd: []const u8, expect_0: bool, argv: []const []const u8) !ChildProcess
7575 if ((code != 0) == expect_0) {
7676 std.debug.warn("The following command exited with error code {}:\n", .{code});
7777 printCmd(cwd, argv);
78 std.debug.warn("stderr:\n{}\n", .{result.stderr});
78 std.debug.warn("stderr:\n{s}\n", .{result.stderr});
7979 return error.CommandFailed;
8080 }
8181 },
8282 else => {
8383 std.debug.warn("The following command terminated unexpectedly:\n", .{});
8484 printCmd(cwd, argv);
85 std.debug.warn("stderr:\n{}\n", .{result.stderr});
85 std.debug.warn("stderr:\n{s}\n", .{result.stderr});
8686 return error.CommandFailed;
8787 },
8888 }
test/standalone/cat/main.zig+1-1
......@@ -41,6 +41,6 @@ pub fn main() !void {
4141}
4242
4343fn usage(exe: []const u8) !void {
44 warn("Usage: {} [FILE]...\n", .{exe});
44 warn("Usage: {s} [FILE]...\n", .{exe});
4545 return error.Invalid;
4646}