Commit 0b1e8690da

r00ster91 <r00ster91@proton.me>
2023-07-04 04:04:30
AstGen: make sure for range start and end are usizes
Fixes #16311 The actual cause of #16311 is the `start_is_zero` special case: ```zig const range_len = if (end_val == .none or start_is_zero) end_val else try parent_gz.addPlNode(.sub, input, Zir.Inst.Bin{ .lhs = end_val, .rhs = start_val, }); ``` It only happens if the range start is 0. In that case we would not perform any type checking. Only in the other cases coincidentally `.sub` performs type checking in Sema, but the errors are still rather poor: ``` $ zig test x.zig x.zig:9:15: error: invalid operands to binary expression: 'Pointer' and 'Pointer' for ("abc".."def") |val| { ~~~~~^~~~~~~ ``` Note how it's the same as if I use `-`: ``` x.zig:9:11: error: invalid operands to binary expression: 'Pointer' and 'Pointer' "abc" - "def"; ~~~~~~^~~~~~~ ``` Now after this PR, the errors are much clearer for both range start and end: ``` x.zig:9:10: error: expected type 'usize', found '*const [3:0]u8' for ("abc".."def") |val| { ^~~~~ ``` This is why I decided to use `.ty` instead of `.coerced_ty` for both range start and end rather than just perform type checking in that `end_val == .none or start_is_zero` case.
1 parent 3bf0b8e
Changed files (2)
src
test
cases
compile_errors
src/AstGen.zig
@@ -6500,11 +6500,11 @@ fn forExpr(
                     return astgen.failTok(ident_tok, "cannot capture reference to range", .{});
                 }
                 const start_node = node_data[input].lhs;
-                const start_val = try expr(parent_gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, start_node);
+                const start_val = try expr(parent_gz, scope, .{ .rl = .{ .ty = .usize_type } }, start_node);
 
                 const end_node = node_data[input].rhs;
                 const end_val = if (end_node != 0)
-                    try expr(parent_gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_data[input].rhs)
+                    try expr(parent_gz, scope, .{ .rl = .{ .ty = .usize_type } }, node_data[input].rhs)
                 else
                     .none;
 
@@ -10339,8 +10339,8 @@ fn nodeUsesAnonNameStrategy(tree: *const Ast, node: Ast.Node.Index) bool {
 
 /// Applies `rl` semantics to `result`. Expressions which do not do their own handling of
 /// result locations must call this function on their result.
-/// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.
-/// If the `ResultLoc` is `ty`, it will coerce the result to the type.
+/// As an example, if `ri.rl` is `.ptr`, it will write the result to the pointer.
+/// If `ri.rl` is `.ty`, it will coerce the result to the type.
 /// Assumes nothing stacked on `gz`.
 fn rvalue(
     gz: *GenZir,
test/cases/compile_errors/for_invalid_ranges.zig
@@ -0,0 +1,35 @@
+export fn a() void {
+    for (0.."hello") |i| {
+        _ = i;
+    }
+}
+export fn b() void {
+    for (-1..-5) |i| {
+        _ = i;
+    }
+}
+export fn c() void {
+    for ("hello"..0) |i| {
+        _ = i;
+    }
+}
+export fn d() void {
+    for (0..&.{ 'a', 'b', 'c' }) |i| {
+        _ = i;
+    }
+}
+export fn e() void {
+    for (@as(u8, 1)..0) |i| {
+        _ = i;
+    }
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :2:13: error: expected type 'usize', found '*const [5:0]u8'
+// :7:10: error: type 'usize' cannot represent integer value '-1'
+// :12:10: error: expected type 'usize', found '*const [5:0]u8'
+// :17:13: error: expected type 'usize', found '*const struct{comptime comptime_int = 97, comptime comptime_int = 98, comptime comptime_int = 99}'
+// :22:20: error: overflow of integer type 'usize' with value '-1'