authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-09 01:19:29-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-09 01:19:29-07:00
log0f0d27ce2427bff9d48d14b829e29a2003ba0e9c
tree756b88c6529fa4e6180335c26f885195d7fc985b
parentbb73775d40e04796b0dd60341303d567db0a8020

Sema: implement tuple fieldptr and fieldval


2 files changed, 56 insertions(+), 18 deletions(-)

src/Sema.zig+51-17
...@@ -5027,6 +5027,7 @@ fn finishGenericCall(...@@ -5027,6 +5027,7 @@ fn finishGenericCall(
5027 try sema.requireRuntimeBlock(block, call_src);5027 try sema.requireRuntimeBlock(block, call_src);
50285028
5029 const comptime_args = callee.comptime_args.?;5029 const comptime_args = callee.comptime_args.?;
5030 const new_fn_info = callee.owner_decl.ty.fnInfo();
5030 const runtime_args_len = count: {5031 const runtime_args_len = count: {
5031 var count: u32 = 0;5032 var count: u32 = 0;
5032 var arg_i: usize = 0;5033 var arg_i: usize = 0;
...@@ -5045,7 +5046,6 @@ fn finishGenericCall(...@@ -5045,7 +5046,6 @@ fn finishGenericCall(
5045 };5046 };
5046 const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len);5047 const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len);
5047 {5048 {
5048 const new_fn_ty = callee.owner_decl.ty;
5049 var runtime_i: u32 = 0;5049 var runtime_i: u32 = 0;
5050 var total_i: u32 = 0;5050 var total_i: u32 = 0;
5051 for (fn_info.param_body) |inst| {5051 for (fn_info.param_body) |inst| {
...@@ -5055,7 +5055,7 @@ fn finishGenericCall(...@@ -5055,7 +5055,7 @@ fn finishGenericCall(
5055 }5055 }
5056 const is_runtime = comptime_args[total_i].val.tag() == .generic_poison;5056 const is_runtime = comptime_args[total_i].val.tag() == .generic_poison;
5057 if (is_runtime) {5057 if (is_runtime) {
5058 const param_ty = new_fn_ty.fnParamType(runtime_i);5058 const param_ty = new_fn_info.param_types[runtime_i];
5059 const arg_src = call_src; // TODO: better source location5059 const arg_src = call_src; // TODO: better source location
5060 const uncasted_arg = uncasted_args[total_i];5060 const uncasted_arg = uncasted_args[total_i];
5061 try sema.resolveTypeFully(block, arg_src, param_ty);5061 try sema.resolveTypeFully(block, arg_src, param_ty);
...@@ -5066,7 +5066,7 @@ fn finishGenericCall(...@@ -5066,7 +5066,7 @@ fn finishGenericCall(
5066 total_i += 1;5066 total_i += 1;
5067 }5067 }
50685068
5069 try sema.resolveTypeFully(block, call_src, new_fn_ty.fnReturnType());5069 try sema.resolveTypeFully(block, call_src, new_fn_info.return_type);
5070 }5070 }
5071 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +5071 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
5072 runtime_args_len);5072 runtime_args_len);
...@@ -15222,6 +15222,19 @@ fn structFieldPtr(...@@ -15222,6 +15222,19 @@ fn structFieldPtr(
1522215222
15223 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);15223 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);
15224 try sema.resolveStructLayout(block, src, struct_ty);15224 try sema.resolveStructLayout(block, src, struct_ty);
15225
15226 if (struct_ty.isTuple()) {
15227 if (mem.eql(u8, field_name, "len")) {
15228 const len_inst = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount());
15229 return sema.analyzeRef(block, src, len_inst);
15230 }
15231 const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src);
15232 return sema.tupleFieldPtr(block, struct_ptr, field_index, src, field_name_src);
15233 } else if (struct_ty.isAnonStruct()) {
15234 const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src);
15235 return sema.tupleFieldPtr(block, struct_ptr, field_index, src, field_name_src);
15236 }
15237
15225 const struct_obj = struct_ty.castTag(.@"struct").?.data;15238 const struct_obj = struct_ty.castTag(.@"struct").?.data;
1522615239
15227 const field_index_big = struct_obj.fields.getIndex(field_name) orelse15240 const field_index_big = struct_obj.fields.getIndex(field_name) orelse
...@@ -15324,15 +15337,7 @@ fn structFieldVal(...@@ -15324,15 +15337,7 @@ fn structFieldVal(
15324 switch (struct_ty.tag()) {15337 switch (struct_ty.tag()) {
15325 .tuple, .empty_struct_literal => return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty),15338 .tuple, .empty_struct_literal => return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty),
15326 .anon_struct => {15339 .anon_struct => {
15327 const anon_struct = struct_ty.castTag(.anon_struct).?.data;15340 const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src);
15328
15329 const field_index = for (anon_struct.names) |name, i| {
15330 if (mem.eql(u8, name, field_name)) break @intCast(u32, i);
15331 } else {
15332 return sema.fail(block, field_name_src, "anonymous struct {} has no such field '{s}'", .{
15333 struct_ty, field_name,
15334 });
15335 };
15336 return tupleFieldValByIndex(sema, block, src, struct_byval, field_index, struct_ty);15341 return tupleFieldValByIndex(sema, block, src, struct_byval, field_index, struct_ty);
15337 },15342 },
15338 .@"struct" => {15343 .@"struct" => {
...@@ -15376,7 +15381,18 @@ fn tupleFieldVal(...@@ -15376,7 +15381,18 @@ fn tupleFieldVal(
15376 if (mem.eql(u8, field_name, "len")) {15381 if (mem.eql(u8, field_name, "len")) {
15377 return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount());15382 return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount());
15378 }15383 }
15384 const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_name_src);
15385 return tupleFieldValByIndex(sema, block, src, tuple_byval, field_index, tuple_ty);
15386}
1537915387
15388/// Don't forget to check for "len" before calling this.
15389fn tupleFieldIndex(
15390 sema: *Sema,
15391 block: *Block,
15392 tuple_ty: Type,
15393 field_name: []const u8,
15394 field_name_src: LazySrcLoc,
15395) CompileError!u32 {
15380 const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| {15396 const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| {
15381 return sema.fail(block, field_name_src, "tuple {} has no such field '{s}': {s}", .{15397 return sema.fail(block, field_name_src, "tuple {} has no such field '{s}': {s}", .{
15382 tuple_ty, field_name, @errorName(err),15398 tuple_ty, field_name, @errorName(err),
...@@ -15387,7 +15403,7 @@ fn tupleFieldVal(...@@ -15387,7 +15403,7 @@ fn tupleFieldVal(
15387 tuple_ty, field_name,15403 tuple_ty, field_name,
15388 });15404 });
15389 }15405 }
15390 return tupleFieldValByIndex(sema, block, src, tuple_byval, field_index, tuple_ty);15406 return field_index;
15391}15407}
1539215408
15393fn tupleFieldValByIndex(15409fn tupleFieldValByIndex(
...@@ -15685,15 +15701,15 @@ fn tupleFieldPtr(...@@ -15685,15 +15701,15 @@ fn tupleFieldPtr(
15685) CompileError!Air.Inst.Ref {15701) CompileError!Air.Inst.Ref {
15686 const tuple_ptr_ty = sema.typeOf(tuple_ptr);15702 const tuple_ptr_ty = sema.typeOf(tuple_ptr);
15687 const tuple_ty = tuple_ptr_ty.childType();15703 const tuple_ty = tuple_ptr_ty.childType();
15688 const tuple_info = tuple_ty.castTag(.tuple).?.data;15704 const tuple = tuple_ty.tupleFields();
1568915705
15690 if (field_index > tuple_info.types.len) {15706 if (field_index > tuple.types.len) {
15691 return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{15707 return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{
15692 field_index, tuple_info.types.len,15708 field_index, tuple.types.len,
15693 });15709 });
15694 }15710 }
1569515711
15696 const field_ty = tuple_info.types[field_index];15712 const field_ty = tuple.types[field_index];
15697 const target = sema.mod.getTarget();15713 const target = sema.mod.getTarget();
15698 const ptr_field_ty = try Type.ptr(sema.arena, target, .{15714 const ptr_field_ty = try Type.ptr(sema.arena, target, .{
15699 .pointee_type = field_ty,15715 .pointee_type = field_ty,
...@@ -20470,3 +20486,21 @@ fn structFieldIndex(...@@ -20470,3 +20486,21 @@ fn structFieldIndex(
20470 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);20486 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
20471 return @intCast(u32, field_index_usize);20487 return @intCast(u32, field_index_usize);
20472}20488}
20489
20490fn anonStructFieldIndex(
20491 sema: *Sema,
20492 block: *Block,
20493 struct_ty: Type,
20494 field_name: []const u8,
20495 field_src: LazySrcLoc,
20496) !u32 {
20497 const anon_struct = struct_ty.castTag(.anon_struct).?.data;
20498 for (anon_struct.names) |name, i| {
20499 if (mem.eql(u8, name, field_name)) {
20500 return @intCast(u32, i);
20501 }
20502 }
20503 return sema.fail(block, field_src, "anonymous struct {} has no such field '{s}'", .{
20504 struct_ty, field_name,
20505 });
20506}
test/behavior/tuple.zig+5-1
...@@ -5,7 +5,11 @@ const expect = testing.expect;...@@ -5,7 +5,11 @@ const expect = testing.expect;
5const expectEqual = testing.expectEqual;5const expectEqual = testing.expectEqual;
66
7test "tuple concatenation" {7test "tuple concatenation" {
8 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
913
10 const S = struct {14 const S = struct {
11 fn doTheTest() !void {15 fn doTheTest() !void {