authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-19 22:39:46-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-10-19 22:39:46-04:00
log4a76523b92bcf0e9b48438cb22f49e67e0ab3fa1
treed8a05453ecd23c9e1dbbc912731958e3b84c9c7a
parent372e9709ad2f4af24461f0fa601754a469091c2b
parentc1508c98f479497c2b2586ea944be9f3ddae28fc
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9984 from Snektron/field-elem-access

Field elem access

12 files changed, 523 insertions(+), 311 deletions(-)

src/Air.zig+8
...@@ -367,6 +367,12 @@ pub const Inst = struct {...@@ -367,6 +367,12 @@ pub const Inst = struct {
367 /// Given a slice value, return the pointer.367 /// Given a slice value, return the pointer.
368 /// Uses the `ty_op` field.368 /// Uses the `ty_op` field.
369 slice_ptr,369 slice_ptr,
370 /// Given a pointer to a slice, return a pointer to the length of the slice.
371 /// Uses the `ty_op` field.
372 ptr_slice_len_ptr,
373 /// Given a pointer to a slice, return a pointer to the pointer of the slice.
374 /// Uses the `ty_op` field.
375 ptr_slice_ptr_ptr,
370 /// Given an array value and element index, return the element value at that index.376 /// Given an array value and element index, return the element value at that index.
371 /// Result type is the element type of the array operand.377 /// Result type is the element type of the array operand.
372 /// Uses the `bin_op` field.378 /// Uses the `bin_op` field.
...@@ -707,6 +713,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -707,6 +713,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
707 .wrap_errunion_payload,713 .wrap_errunion_payload,
708 .wrap_errunion_err,714 .wrap_errunion_err,
709 .slice_ptr,715 .slice_ptr,
716 .ptr_slice_len_ptr,
717 .ptr_slice_ptr_ptr,
710 .struct_field_ptr_index_0,718 .struct_field_ptr_index_0,
711 .struct_field_ptr_index_1,719 .struct_field_ptr_index_1,
712 .struct_field_ptr_index_2,720 .struct_field_ptr_index_2,
src/AstGen.zig+16-21
...@@ -193,9 +193,6 @@ pub const ResultLoc = union(enum) {...@@ -193,9 +193,6 @@ pub const ResultLoc = union(enum) {
193 /// The expression must generate a pointer rather than a value. For example, the left hand side193 /// The expression must generate a pointer rather than a value. For example, the left hand side
194 /// of an assignment uses this kind of result location.194 /// of an assignment uses this kind of result location.
195 ref,195 ref,
196 /// The callee will accept a ref, but it is not necessary, and the `ResultLoc`
197 /// may be treated as `none` instead.
198 none_or_ref,
199 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.196 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.
200 ty: Zir.Inst.Ref,197 ty: Zir.Inst.Ref,
201 /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion,198 /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion,
...@@ -231,7 +228,7 @@ pub const ResultLoc = union(enum) {...@@ -231,7 +228,7 @@ pub const ResultLoc = union(enum) {
231 fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy {228 fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy {
232 switch (rl) {229 switch (rl) {
233 // In this branch there will not be any store_to_block_ptr instructions.230 // In this branch there will not be any store_to_block_ptr instructions.
234 .discard, .none, .none_or_ref, .ty, .coerced_ty, .ref => return .{231 .discard, .none, .ty, .coerced_ty, .ref => return .{
235 .tag = .break_operand,232 .tag = .break_operand,
236 .elide_store_to_block_ptr_instructions = false,233 .elide_store_to_block_ptr_instructions = false,
237 },234 },
...@@ -727,7 +724,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -727,7 +724,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
727 .start = start,724 .start = start,
728 });725 });
729 switch (rl) {726 switch (rl) {
730 .ref, .none_or_ref => return result,727 .ref => return result,
731 else => {728 else => {
732 const dereffed = try gz.addUnNode(.load, result, node);729 const dereffed = try gz.addUnNode(.load, result, node);
733 return rvalue(gz, rl, dereffed, node);730 return rvalue(gz, rl, dereffed, node);
...@@ -745,7 +742,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -745,7 +742,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
745 .end = end,742 .end = end,
746 });743 });
747 switch (rl) {744 switch (rl) {
748 .ref, .none_or_ref => return result,745 .ref => return result,
749 else => {746 else => {
750 const dereffed = try gz.addUnNode(.load, result, node);747 const dereffed = try gz.addUnNode(.load, result, node);
751 return rvalue(gz, rl, dereffed, node);748 return rvalue(gz, rl, dereffed, node);
...@@ -765,7 +762,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -765,7 +762,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
765 .sentinel = sentinel,762 .sentinel = sentinel,
766 });763 });
767 switch (rl) {764 switch (rl) {
768 .ref, .none_or_ref => return result,765 .ref => return result,
769 else => {766 else => {
770 const dereffed = try gz.addUnNode(.load, result, node);767 const dereffed = try gz.addUnNode(.load, result, node);
771 return rvalue(gz, rl, dereffed, node);768 return rvalue(gz, rl, dereffed, node);
...@@ -776,7 +773,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -776,7 +773,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
776 .deref => {773 .deref => {
777 const lhs = try expr(gz, scope, .none, node_datas[node].lhs);774 const lhs = try expr(gz, scope, .none, node_datas[node].lhs);
778 switch (rl) {775 switch (rl) {
779 .ref, .none_or_ref => return lhs,776 .ref => return lhs,
780 else => {777 else => {
781 const result = try gz.addUnNode(.load, lhs, node);778 const result = try gz.addUnNode(.load, lhs, node);
782 return rvalue(gz, rl, result, node);779 return rvalue(gz, rl, result, node);
...@@ -1273,7 +1270,7 @@ fn arrayInitExpr(...@@ -1273,7 +1270,7 @@ fn arrayInitExpr(
1273 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref);1270 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref);
1274 }1271 }
1275 },1272 },
1276 .none, .none_or_ref => {1273 .none => {
1277 if (types.array != .none) {1274 if (types.array != .none) {
1278 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);1275 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);
1279 } else {1276 } else {
...@@ -1475,7 +1472,7 @@ fn structInitExpr(...@@ -1475,7 +1472,7 @@ fn structInitExpr(
1475 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref);1472 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref);
1476 }1473 }
1477 },1474 },
1478 .none, .none_or_ref => {1475 .none => {
1479 if (struct_init.ast.type_expr != 0) {1476 if (struct_init.ast.type_expr != 0) {
1480 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);1477 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1481 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);1478 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
...@@ -5133,7 +5130,7 @@ fn fieldAccess(...@@ -5133,7 +5130,7 @@ fn fieldAccess(
5133 if (rl == .ref) {5130 if (rl == .ref) {
5134 return addFieldAccess(.field_ptr, gz, scope, .ref, node);5131 return addFieldAccess(.field_ptr, gz, scope, .ref, node);
5135 } else {5132 } else {
5136 const access = try addFieldAccess(.field_val, gz, scope, .none_or_ref, node);5133 const access = try addFieldAccess(.field_val, gz, scope, .none, node);
5137 return rvalue(gz, rl, access, node);5134 return rvalue(gz, rl, access, node);
5138 }5135 }
5139}5136}
...@@ -5178,7 +5175,7 @@ fn arrayAccess(...@@ -5178,7 +5175,7 @@ fn arrayAccess(
5178 ),5175 ),
5179 else => return rvalue(gz, rl, try gz.addBin(5176 else => return rvalue(gz, rl, try gz.addBin(
5180 .elem_val,5177 .elem_val,
5181 try expr(gz, scope, .none_or_ref, node_datas[node].lhs),5178 try expr(gz, scope, .none, node_datas[node].lhs),
5182 try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),5179 try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),
5183 ), node),5180 ), node),
5184 }5181 }
...@@ -6664,7 +6661,7 @@ fn identifier(...@@ -6664,7 +6661,7 @@ fn identifier(
6664 );6661 );
66656662
6666 switch (rl) {6663 switch (rl) {
6667 .ref, .none_or_ref => return ptr_inst,6664 .ref => return ptr_inst,
6668 else => {6665 else => {
6669 const loaded = try gz.addUnNode(.load, ptr_inst, ident);6666 const loaded = try gz.addUnNode(.load, ptr_inst, ident);
6670 return rvalue(gz, rl, loaded, ident);6667 return rvalue(gz, rl, loaded, ident);
...@@ -6700,7 +6697,7 @@ fn identifier(...@@ -6700,7 +6697,7 @@ fn identifier(
6700 // Decl references happen by name rather than ZIR index so that when unrelated6697 // Decl references happen by name rather than ZIR index so that when unrelated
6701 // decls are modified, ZIR code containing references to them can be unmodified.6698 // decls are modified, ZIR code containing references to them can be unmodified.
6702 switch (rl) {6699 switch (rl) {
6703 .ref, .none_or_ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token),6700 .ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
6704 else => {6701 else => {
6705 const result = try gz.addStrTok(.decl_val, name_str_index, ident_token);6702 const result = try gz.addStrTok(.decl_val, name_str_index, ident_token);
6706 return rvalue(gz, rl, result, ident);6703 return rvalue(gz, rl, result, ident);
...@@ -7105,7 +7102,7 @@ fn as(...@@ -7105,7 +7102,7 @@ fn as(
7105) InnerError!Zir.Inst.Ref {7102) InnerError!Zir.Inst.Ref {
7106 const dest_type = try typeExpr(gz, scope, lhs);7103 const dest_type = try typeExpr(gz, scope, lhs);
7107 switch (rl) {7104 switch (rl) {
7108 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty => {7105 .none, .discard, .ref, .ty, .coerced_ty => {
7109 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);7106 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);
7110 return rvalue(gz, rl, result, node);7107 return rvalue(gz, rl, result, node);
7111 },7108 },
...@@ -7128,7 +7125,7 @@ fn unionInit(...@@ -7128,7 +7125,7 @@ fn unionInit(
7128 const union_type = try typeExpr(gz, scope, params[0]);7125 const union_type = try typeExpr(gz, scope, params[0]);
7129 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);7126 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
7130 switch (rl) {7127 switch (rl) {
7131 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => {7128 .none, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => {
7132 _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{7129 _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{
7133 .container_type = union_type,7130 .container_type = union_type,
7134 .field_name = field_name,7131 .field_name = field_name,
...@@ -7192,7 +7189,7 @@ fn bitCast(...@@ -7192,7 +7189,7 @@ fn bitCast(
7192 const astgen = gz.astgen;7189 const astgen = gz.astgen;
7193 const dest_type = try typeExpr(gz, scope, lhs);7190 const dest_type = try typeExpr(gz, scope, lhs);
7194 switch (rl) {7191 switch (rl) {
7195 .none, .none_or_ref, .discard, .ty, .coerced_ty => {7192 .none, .discard, .ty, .coerced_ty => {
7196 const operand = try expr(gz, scope, .none, rhs);7193 const operand = try expr(gz, scope, .none, rhs);
7197 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{7194 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{
7198 .lhs = dest_type,7195 .lhs = dest_type,
...@@ -8799,7 +8796,7 @@ fn rvalue(...@@ -8799,7 +8796,7 @@ fn rvalue(
8799) InnerError!Zir.Inst.Ref {8796) InnerError!Zir.Inst.Ref {
8800 if (gz.endsWithNoReturn()) return result;8797 if (gz.endsWithNoReturn()) return result;
8801 switch (rl) {8798 switch (rl) {
8802 .none, .none_or_ref, .coerced_ty => return result,8799 .none, .coerced_ty => return result,
8803 .discard => {8800 .discard => {
8804 // Emit a compile error for discarding error values.8801 // Emit a compile error for discarding error values.
8805 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);8802 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
...@@ -9561,9 +9558,7 @@ const GenZir = struct {...@@ -9561,9 +9558,7 @@ const GenZir = struct {
9561 gz.rl_ty_inst = ty_inst;9558 gz.rl_ty_inst = ty_inst;
9562 gz.break_result_loc = parent_rl;9559 gz.break_result_loc = parent_rl;
9563 },9560 },
9564 .none_or_ref => {9561
9565 gz.break_result_loc = .ref;
9566 },
9567 .discard, .none, .ptr, .ref => {9562 .discard, .none, .ptr, .ref => {
9568 gz.break_result_loc = parent_rl;9563 gz.break_result_loc = parent_rl;
9569 },9564 },
src/Liveness.zig+2
...@@ -300,6 +300,8 @@ fn analyzeInst(...@@ -300,6 +300,8 @@ fn analyzeInst(
300 .wrap_errunion_err,300 .wrap_errunion_err,
301 .slice_ptr,301 .slice_ptr,
302 .slice_len,302 .slice_len,
303 .ptr_slice_len_ptr,
304 .ptr_slice_ptr_ptr,
303 .struct_field_ptr_index_0,305 .struct_field_ptr_index_0,
304 .struct_field_ptr_index_1,306 .struct_field_ptr_index_1,
305 .struct_field_ptr_index_2,307 .struct_field_ptr_index_2,
src/Sema.zig+291-234
...@@ -300,7 +300,7 @@ pub const Block = struct {...@@ -300,7 +300,7 @@ pub const Block = struct {
300 .ty = ty,300 .ty = ty,
301 .payload = try block.sema.addExtra(Air.StructField{301 .payload = try block.sema.addExtra(Air.StructField{
302 .struct_operand = struct_ptr,302 .struct_operand = struct_ptr,
303 .field_index = @intCast(u32, field_index),303 .field_index = field_index,
304 }),304 }),
305 } },305 } },
306 });306 });
...@@ -315,6 +315,24 @@ pub const Block = struct {...@@ -315,6 +315,24 @@ pub const Block = struct {
315 });315 });
316 }316 }
317317
318 pub fn addStructFieldVal(
319 block: *Block,
320 struct_val: Air.Inst.Ref,
321 field_index: u32,
322 field_ty: Type,
323 ) !Air.Inst.Ref {
324 return block.addInst(.{
325 .tag = .struct_field_val,
326 .data = .{ .ty_pl = .{
327 .ty = try block.sema.addType(field_ty),
328 .payload = try block.sema.addExtra(Air.StructField{
329 .struct_operand = struct_val,
330 .field_index = field_index,
331 }),
332 } },
333 });
334 }
335
318 pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {336 pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {
319 return Air.indexToRef(try block.addInstAsIndex(inst));337 return Air.indexToRef(try block.addInstAsIndex(inst));
320 }338 }
...@@ -1968,44 +1986,38 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1968,44 +1986,38 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
19681986
1969 const inst_data = sema.code.instructions.items(.data)[inst].un_node;1987 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1970 const src = inst_data.src();1988 const src = inst_data.src();
1971 const array = sema.resolveInst(inst_data.operand);1989 const object = sema.resolveInst(inst_data.operand);
1972 const array_ty = sema.typeOf(array);1990 const object_ty = sema.typeOf(object);
19731991
1974 if (array_ty.isSlice()) {1992 const is_pointer_to = object_ty.isSinglePointer();
1975 return sema.analyzeSliceLen(block, src, array);
1976 }
19771993
1978 if (array_ty.isSinglePointer()) {1994 const array_ty = if (is_pointer_to)
1979 const elem_ty = array_ty.elemType();1995 object_ty.childType()
1980 if (elem_ty.isSlice()) {1996 else
1981 const slice_inst = try sema.analyzeLoad(block, src, array, src);1997 object_ty;
1982 return sema.analyzeSliceLen(block, src, slice_inst);1998
1983 }1999 if (!array_ty.isIndexable()) {
1984 if (!elem_ty.isIndexable()) {2000 const msg = msg: {
1985 const msg = msg: {2001 const msg = try sema.errMsg(
1986 const msg = try sema.errMsg(2002 block,
1987 block,2003 src,
1988 src,2004 "type '{}' does not support indexing",
1989 "type '{}' does not support indexing",2005 .{array_ty},
1990 .{elem_ty},2006 );
1991 );2007 errdefer msg.destroy(sema.gpa);
1992 errdefer msg.destroy(sema.gpa);2008 try sema.errNote(
1993 try sema.errNote(2009 block,
1994 block,2010 src,
1995 src,2011 msg,
1996 msg,2012 "for loop operand must be an array, slice, tuple, or vector",
1997 "for loop operand must be an array, slice, tuple, or vector",2013 .{},
1998 .{},2014 );
1999 );2015 break :msg msg;
2000 break :msg msg;2016 };
2001 };2017 return sema.failWithOwnedErrorMsg(msg);
2002 return sema.failWithOwnedErrorMsg(msg);
2003 }
2004 const result_ptr = try sema.fieldPtr(block, src, array, "len", src);
2005 return sema.analyzeLoad(block, src, result_ptr, src);
2006 }2018 }
20072019
2008 return sema.fail(block, src, "TODO implement Sema.zirIndexablePtrLen", .{});2020 return sema.fieldVal(block, src, object, "len", src);
2009}2021}
20102022
2011fn zirAllocExtended(2023fn zirAllocExtended(
...@@ -2304,7 +2316,7 @@ fn validateStructInit(...@@ -2304,7 +2316,7 @@ fn validateStructInit(
2304 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;2316 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
2305 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);2317 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
2306 const field_index = struct_obj.fields.getIndex(field_name) orelse2318 const field_index = struct_obj.fields.getIndex(field_name) orelse
2307 return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name);2319 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
2308 if (found_fields[field_index] != 0) {2320 if (found_fields[field_index] != 0) {
2309 const other_field_ptr = found_fields[field_index];2321 const other_field_ptr = found_fields[field_index];
2310 const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;2322 const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;
...@@ -2366,7 +2378,32 @@ fn zirValidateArrayInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil...@@ -2366,7 +2378,32 @@ fn zirValidateArrayInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
2366 }2378 }
2367}2379}
23682380
2369fn failWithBadFieldAccess(2381fn failWithBadMemberAccess(
2382 sema: *Sema,
2383 block: *Block,
2384 agg_ty: Type,
2385 field_src: LazySrcLoc,
2386 field_name: []const u8,
2387) CompileError {
2388 const kw_name = switch (agg_ty.zigTypeTag()) {
2389 .Union => "union",
2390 .Struct => "struct",
2391 .Opaque => "opaque",
2392 .Enum => "enum",
2393 else => unreachable,
2394 };
2395 const msg = msg: {
2396 const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{s}'", .{
2397 kw_name, agg_ty, field_name,
2398 });
2399 errdefer msg.destroy(sema.gpa);
2400 try sema.addDeclaredHereNote(msg, agg_ty);
2401 break :msg msg;
2402 };
2403 return sema.failWithOwnedErrorMsg(msg);
2404}
2405
2406fn failWithBadStructFieldAccess(
2370 sema: *Sema,2407 sema: *Sema,
2371 block: *Block,2408 block: *Block,
2372 struct_obj: *Module.Struct,2409 struct_obj: *Module.Struct,
...@@ -5119,16 +5156,10 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -5119,16 +5156,10 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
5119 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;5156 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
5120 const src = inst_data.src();5157 const src = inst_data.src();
5121 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };5158 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
5122 const lhs_src: LazySrcLoc = src; // TODO
5123 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;5159 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
5124 const field_name = sema.code.nullTerminatedString(extra.field_name_start);5160 const field_name = sema.code.nullTerminatedString(extra.field_name_start);
5125 const object = sema.resolveInst(extra.lhs);5161 const object = sema.resolveInst(extra.lhs);
5126 if (sema.typeOf(object).isSinglePointer()) {5162 return sema.fieldVal(block, src, object, field_name, field_name_src);
5127 const result_ptr = try sema.fieldPtr(block, src, object, field_name, field_name_src);
5128 return sema.analyzeLoad(block, src, result_ptr, lhs_src);
5129 } else {
5130 return sema.fieldVal(block, src, object, field_name, field_name_src);
5131 }
5132}5163}
51335164
5134fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {5165fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -8822,7 +8853,7 @@ fn zirStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool)...@@ -8822,7 +8853,7 @@ fn zirStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool)
8822 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;8853 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
8823 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);8854 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
8824 const field_index = struct_obj.fields.getIndex(field_name) orelse8855 const field_index = struct_obj.fields.getIndex(field_name) orelse
8825 return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name);8856 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
8826 if (found_fields[field_index] != 0) {8857 if (found_fields[field_index] != 0) {
8827 const other_field_type = found_fields[field_index];8858 const other_field_type = found_fields[field_index];
8828 const other_field_type_data = zir_datas[other_field_type].pl_node;8859 const other_field_type_data = zir_datas[other_field_type].pl_node;
...@@ -9031,7 +9062,7 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -9031,7 +9062,7 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
9031 .Struct => {9062 .Struct => {
9032 const struct_obj = resolved_ty.castTag(.@"struct").?.data;9063 const struct_obj = resolved_ty.castTag(.@"struct").?.data;
9033 const field = struct_obj.fields.get(field_name) orelse9064 const field = struct_obj.fields.get(field_name) orelse
9034 return sema.failWithBadFieldAccess(block, struct_obj, src, field_name);9065 return sema.failWithBadStructFieldAccess(block, struct_obj, src, field_name);
9035 return sema.addType(field.ty);9066 return sema.addType(field.ty);
9036 },9067 },
9037 .Union => {9068 .Union => {
...@@ -9331,7 +9362,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9331,7 +9362,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9331 const dest_info = dest_ty.intInfo(target);9362 const dest_info = dest_ty.intInfo(target);
93329363
9333 if (src_info.bits == 0 or dest_info.bits == 0) {9364 if (src_info.bits == 0 or dest_info.bits == 0) {
9334 return sema.addConstant(dest_ty, Value.initTag(.zero));9365 return sema.addConstant(dest_ty, Value.zero);
9335 }9366 }
93369367
9337 if (!src_is_comptime_int) {9368 if (!src_is_comptime_int) {
...@@ -10688,12 +10719,22 @@ fn fieldVal(...@@ -10688,12 +10719,22 @@ fn fieldVal(
10688 const object_src = src; // TODO better source location10719 const object_src = src; // TODO better source location
10689 const object_ty = sema.typeOf(object);10720 const object_ty = sema.typeOf(object);
1069010721
10691 switch (object_ty.zigTypeTag()) {10722 // Zig allows dereferencing a single pointer during field lookup. Note that
10723 // we don't actually need to generate the dereference some field lookups, like the
10724 // length of arrays and other comptime operations.
10725 const is_pointer_to = object_ty.isSinglePointer();
10726
10727 const inner_ty = if (is_pointer_to)
10728 object_ty.childType()
10729 else
10730 object_ty;
10731
10732 switch (inner_ty.zigTypeTag()) {
10692 .Array => {10733 .Array => {
10693 if (mem.eql(u8, field_name, "len")) {10734 if (mem.eql(u8, field_name, "len")) {
10694 return sema.addConstant(10735 return sema.addConstant(
10695 Type.initTag(.comptime_int),10736 Type.initTag(.comptime_int),
10696 try Value.Tag.int_u64.create(arena, object_ty.arrayLen()),10737 try Value.Tag.int_u64.create(arena, inner_ty.arrayLen()),
10697 );10738 );
10698 } else {10739 } else {
10699 return sema.fail(10740 return sema.fail(
...@@ -10704,75 +10745,60 @@ fn fieldVal(...@@ -10704,75 +10745,60 @@ fn fieldVal(
10704 );10745 );
10705 }10746 }
10706 },10747 },
10707 .Pointer => switch (object_ty.ptrSize()) {10748 .Pointer => if (inner_ty.isSlice()) {
10708 .Slice => {10749 if (mem.eql(u8, field_name, "ptr")) {
10709 if (mem.eql(u8, field_name, "ptr")) {10750 const slice = if (is_pointer_to)
10710 const buf = try arena.create(Type.SlicePtrFieldTypeBuffer);10751 try sema.analyzeLoad(block, src, object, object_src)
10711 const result_ty = object_ty.slicePtrFieldType(buf);10752 else
10712 if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| {10753 object;
10713 if (val.isUndef()) return sema.addConstUndef(result_ty);10754
10714 return sema.addConstant(result_ty, val.slicePtr());10755 const buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
10715 }10756 const result_ty = inner_ty.slicePtrFieldType(buf);
10716 try sema.requireRuntimeBlock(block, src);10757
10717 return block.addTyOp(.slice_ptr, result_ty, object);10758 if (try sema.resolveMaybeUndefVal(block, object_src, slice)) |val| {
10718 } else if (mem.eql(u8, field_name, "len")) {10759 if (val.isUndef()) return sema.addConstUndef(result_ty);
10719 const result_ty = Type.usize;10760 return sema.addConstant(result_ty, val.slicePtr());
10720 if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| {
10721 if (val.isUndef()) return sema.addConstUndef(result_ty);
10722 return sema.addConstant(
10723 result_ty,
10724 try Value.Tag.int_u64.create(arena, val.sliceLen()),
10725 );
10726 }
10727 try sema.requireRuntimeBlock(block, src);
10728 return block.addTyOp(.slice_len, result_ty, object);
10729 } else {
10730 return sema.fail(
10731 block,
10732 field_name_src,
10733 "no member named '{s}' in '{}'",
10734 .{ field_name, object_ty },
10735 );
10736 }10761 }
10737 },10762 try sema.requireRuntimeBlock(block, src);
10738 .One => {10763 return block.addTyOp(.slice_ptr, result_ty, slice);
10739 const ptr_child = object_ty.elemType();10764 } else if (mem.eql(u8, field_name, "len")) {
10740 switch (ptr_child.zigTypeTag()) {10765 const slice = if (is_pointer_to)
10741 .Array => {10766 try sema.analyzeLoad(block, src, object, object_src)
10742 if (mem.eql(u8, field_name, "len")) {10767 else
10743 return sema.addConstant(10768 object;
10744 Type.initTag(.comptime_int),10769
10745 try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()),10770 const result_ty = Type.usize;
10746 );10771
10747 } else {10772 if (try sema.resolveMaybeUndefVal(block, object_src, slice)) |val| {
10748 return sema.fail(10773 if (val.isUndef()) return sema.addConstUndef(result_ty);
10749 block,10774 return sema.addConstant(
10750 field_name_src,10775 result_ty,
10751 "no member named '{s}' in '{}'",10776 try Value.Tag.int_u64.create(arena, val.sliceLen()),
10752 .{ field_name, object_ty },10777 );
10753 );
10754 }
10755 },
10756 .Struct => {
10757 const struct_ptr_deref = try sema.analyzeLoad(block, src, object, object_src);
10758 return sema.unionFieldVal(block, src, struct_ptr_deref, field_name, field_name_src, ptr_child);
10759 },
10760 .Union => {
10761 const union_ptr_deref = try sema.analyzeLoad(block, src, object, object_src);
10762 return sema.unionFieldVal(block, src, union_ptr_deref, field_name, field_name_src, ptr_child);
10763 },
10764 else => {},
10765 }10778 }
10766 },10779 try sema.requireRuntimeBlock(block, src);
10767 .Many, .C => {},10780 return block.addTyOp(.slice_len, result_ty, slice);
10781 } else {
10782 return sema.fail(
10783 block,
10784 field_name_src,
10785 "no member named '{s}' in '{}'",
10786 .{ field_name, object_ty },
10787 );
10788 }
10768 },10789 },
10769 .Type => {10790 .Type => {
10770 const val = (try sema.resolveDefinedValue(block, object_src, object)).?;10791 const dereffed_type = if (is_pointer_to)
10792 try sema.analyzeLoad(block, src, object, object_src)
10793 else
10794 object;
10795
10796 const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?;
10771 var to_type_buffer: Value.ToTypeBuffer = undefined;10797 var to_type_buffer: Value.ToTypeBuffer = undefined;
10772 const child_type = val.toType(&to_type_buffer);10798 const child_type = val.toType(&to_type_buffer);
10799
10773 switch (child_type.zigTypeTag()) {10800 switch (child_type.zigTypeTag()) {
10774 .ErrorSet => {10801 .ErrorSet => {
10775 // TODO resolve inferred error sets
10776 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {10802 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {
10777 const error_set = payload.data;10803 const error_set = payload.data;
10778 // TODO this is O(N). I'm putting off solving this until we solve inferred10804 // TODO this is O(N). I'm putting off solving this until we solve inferred
...@@ -10842,8 +10868,20 @@ fn fieldVal(...@@ -10842,8 +10868,20 @@ fn fieldVal(
10842 else => return sema.fail(block, src, "type '{}' has no members", .{child_type}),10868 else => return sema.fail(block, src, "type '{}' has no members", .{child_type}),
10843 }10869 }
10844 },10870 },
10845 .Struct => return sema.structFieldVal(block, src, object, field_name, field_name_src, object_ty),10871 .Struct => if (is_pointer_to) {
10846 .Union => return sema.unionFieldVal(block, src, object, field_name, field_name_src, object_ty),10872 // Avoid loading the entire struct by fetching a pointer and loading that
10873 const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty);
10874 return sema.analyzeLoad(block, src, field_ptr, object_src);
10875 } else {
10876 return sema.structFieldVal(block, src, object, field_name, field_name_src, inner_ty);
10877 },
10878 .Union => if (is_pointer_to) {
10879 // Avoid loading the entire union by fetching a pointer and loading that
10880 const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty);
10881 return sema.analyzeLoad(block, src, field_ptr, object_src);
10882 } else {
10883 return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty);
10884 },
10847 else => {},10885 else => {},
10848 }10886 }
10849 return sema.fail(block, src, "type '{}' does not support field access", .{object_ty});10887 return sema.fail(block, src, "type '{}' does not support field access", .{object_ty});
...@@ -10866,14 +10904,25 @@ fn fieldPtr(...@@ -10866,14 +10904,25 @@ fn fieldPtr(
10866 .Pointer => object_ptr_ty.elemType(),10904 .Pointer => object_ptr_ty.elemType(),
10867 else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty}),10905 else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty}),
10868 };10906 };
10869 switch (object_ty.zigTypeTag()) {10907
10908 // Zig allows dereferencing a single pointer during field lookup. Note that
10909 // we don't actually need to generate the dereference some field lookups, like the
10910 // length of arrays and other comptime operations.
10911 const is_pointer_to = object_ty.isSinglePointer();
10912
10913 const inner_ty = if (is_pointer_to)
10914 object_ty.childType()
10915 else
10916 object_ty;
10917
10918 switch (inner_ty.zigTypeTag()) {
10870 .Array => {10919 .Array => {
10871 if (mem.eql(u8, field_name, "len")) {10920 if (mem.eql(u8, field_name, "len")) {
10872 var anon_decl = try block.startAnonDecl();10921 var anon_decl = try block.startAnonDecl();
10873 defer anon_decl.deinit();10922 defer anon_decl.deinit();
10874 return sema.analyzeDeclRef(try anon_decl.finish(10923 return sema.analyzeDeclRef(try anon_decl.finish(
10875 Type.initTag(.comptime_int),10924 Type.initTag(.comptime_int),
10876 try Value.Tag.int_u64.create(anon_decl.arena(), object_ty.arrayLen()),10925 try Value.Tag.int_u64.create(anon_decl.arena(), inner_ty.arrayLen()),
10877 ));10926 ));
10878 } else {10927 } else {
10879 return sema.fail(10928 return sema.fail(
...@@ -10884,77 +10933,74 @@ fn fieldPtr(...@@ -10884,77 +10933,74 @@ fn fieldPtr(
10884 );10933 );
10885 }10934 }
10886 },10935 },
10887 .Pointer => switch (object_ty.ptrSize()) {10936 .Pointer => if (inner_ty.isSlice()) {
10888 .Slice => {10937 const inner_ptr = if (is_pointer_to)
10889 // Here for the ptr and len fields what we need to do is the situation10938 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
10890 // when a temporary has its address taken, e.g. `&a[c..d].len`.10939 else
10891 // This value may be known at compile-time or runtime. In the former10940 object_ptr;
10892 // case, it should create an anonymous Decl and return a decl_ref to it.10941
10893 // In the latter case, it should add an `alloc` instruction, store10942 if (mem.eql(u8, field_name, "ptr")) {
10894 // the runtime value to it, and then return the `alloc`.10943 const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer);
10895 // In both cases the pointer should be const.10944 const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);
10896 if (mem.eql(u8, field_name, "ptr")) {10945
10897 return sema.fail(10946 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
10898 block,10947 var anon_decl = try block.startAnonDecl();
10899 field_name_src,10948 defer anon_decl.deinit();
10900 "TODO: implement reference to 'ptr' field of slice '{}'",10949
10901 .{object_ty},10950 return sema.analyzeDeclRef(try anon_decl.finish(
10902 );10951 try slice_ptr_ty.copy(anon_decl.arena()),
10903 } else if (mem.eql(u8, field_name, "len")) {10952 try val.slicePtr().copy(anon_decl.arena()),
10904 return sema.fail(10953 ));
10905 block,
10906 field_name_src,
10907 "TODO: implement reference to 'len' field of slice '{}'",
10908 .{object_ty},
10909 );
10910 } else {
10911 return sema.fail(
10912 block,
10913 field_name_src,
10914 "no member named '{s}' in '{}'",
10915 .{ field_name, object_ty },
10916 );
10917 }10954 }
10918 },10955 try sema.requireRuntimeBlock(block, src);
10919 .One => {10956
10920 const ptr_child = object_ty.elemType();10957 const result_ty = try Type.ptr(sema.arena, .{
10921 switch (ptr_child.zigTypeTag()) {10958 .pointee_type = slice_ptr_ty,
10922 .Array => {10959 .mutable = object_ptr_ty.ptrIsMutable(),
10923 if (mem.eql(u8, field_name, "len")) {10960 .@"addrspace" = object_ptr_ty.ptrAddressSpace(),
10924 var anon_decl = try block.startAnonDecl();10961 });
10925 defer anon_decl.deinit();10962
10926 return sema.analyzeDeclRef(try anon_decl.finish(10963 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
10927 Type.initTag(.comptime_int),10964 } else if (mem.eql(u8, field_name, "len")) {
10928 try Value.Tag.int_u64.create(anon_decl.arena(), ptr_child.arrayLen()),10965 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
10929 ));10966 var anon_decl = try block.startAnonDecl();
10930 } else {10967 defer anon_decl.deinit();
10931 return sema.fail(10968
10932 block,10969 return sema.analyzeDeclRef(try anon_decl.finish(
10933 field_name_src,10970 Type.usize,
10934 "no member named '{s}' in '{}'",10971 try Value.Tag.int_u64.create(anon_decl.arena(), val.sliceLen()),
10935 .{ field_name, object_ty },10972 ));
10936 );
10937 }
10938 },
10939 .Struct => {
10940 const struct_ptr_deref = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src);
10941 return sema.structFieldPtr(block, src, struct_ptr_deref, field_name, field_name_src, ptr_child);
10942 },
10943 .Union => {
10944 const union_ptr_deref = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src);
10945 return sema.unionFieldPtr(block, src, union_ptr_deref, field_name, field_name_src, ptr_child);
10946 },
10947 else => {},
10948 }10973 }
10949 },10974 try sema.requireRuntimeBlock(block, src);
10950 .Many, .C => {},10975
10976 const result_ty = try Type.ptr(sema.arena, .{
10977 .pointee_type = Type.usize,
10978 .mutable = object_ptr_ty.ptrIsMutable(),
10979 .@"addrspace" = object_ptr_ty.ptrAddressSpace(),
10980 });
10981
10982 return block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr);
10983 } else {
10984 return sema.fail(
10985 block,
10986 field_name_src,
10987 "no member named '{s}' in '{}'",
10988 .{ field_name, object_ty },
10989 );
10990 }
10951 },10991 },
10952 .Type => {10992 .Type => {
10953 _ = try sema.resolveConstValue(block, object_ptr_src, object_ptr);10993 _ = try sema.resolveConstValue(block, object_ptr_src, object_ptr);
10954 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src);10994 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src);
10955 const val = (sema.resolveDefinedValue(block, src, result) catch unreachable).?;10995 const inner = if (is_pointer_to)
10996 try sema.analyzeLoad(block, src, result, object_ptr_src)
10997 else
10998 result;
10999
11000 const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?;
10956 var to_type_buffer: Value.ToTypeBuffer = undefined;11001 var to_type_buffer: Value.ToTypeBuffer = undefined;
10957 const child_type = val.toType(&to_type_buffer);11002 const child_type = val.toType(&to_type_buffer);
11003
10958 switch (child_type.zigTypeTag()) {11004 switch (child_type.zigTypeTag()) {
10959 .ErrorSet => {11005 .ErrorSet => {
10960 // TODO resolve inferred error sets11006 // TODO resolve inferred error sets
...@@ -10980,22 +11026,24 @@ fn fieldPtr(...@@ -10980,22 +11026,24 @@ fn fieldPtr(
10980 try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),11026 try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),
10981 ));11027 ));
10982 },11028 },
10983 .Struct, .Opaque, .Union => {11029 .Union => {
10984 if (child_type.getNamespace()) |namespace| {11030 if (child_type.getNamespace()) |namespace| {
10985 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {11031 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
10986 return inst;11032 return inst;
10987 }11033 }
10988 }11034 }
10989 // TODO add note: declared here11035 if (child_type.unionTagType()) |enum_ty| {
10990 const kw_name = switch (child_type.zigTypeTag()) {11036 if (enum_ty.enumFieldIndex(field_name)) |field_index| {
10991 .Struct => "struct",11037 const field_index_u32 = @intCast(u32, field_index);
10992 .Opaque => "opaque",11038 var anon_decl = try block.startAnonDecl();
10993 .Union => "union",11039 defer anon_decl.deinit();
10994 else => unreachable,11040 return sema.analyzeDeclRef(try anon_decl.finish(
10995 };11041 try enum_ty.copy(anon_decl.arena()),
10996 return sema.fail(block, src, "{s} '{}' has no member named '{s}'", .{11042 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
10997 kw_name, child_type, field_name,11043 ));
10998 });11044 }
11045 }
11046 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
10999 },11047 },
11000 .Enum => {11048 .Enum => {
11001 if (child_type.getNamespace()) |namespace| {11049 if (child_type.getNamespace()) |namespace| {
...@@ -11004,23 +11052,7 @@ fn fieldPtr(...@@ -11004,23 +11052,7 @@ fn fieldPtr(
11004 }11052 }
11005 }11053 }
11006 const field_index = child_type.enumFieldIndex(field_name) orelse {11054 const field_index = child_type.enumFieldIndex(field_name) orelse {
11007 const msg = msg: {11055 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
11008 const msg = try sema.errMsg(
11009 block,
11010 src,
11011 "enum '{}' has no member named '{s}'",
11012 .{ child_type, field_name },
11013 );
11014 errdefer msg.destroy(sema.gpa);
11015 try sema.mod.errNoteNonLazy(
11016 child_type.declSrcLoc(),
11017 msg,
11018 "enum declared here",
11019 .{},
11020 );
11021 break :msg msg;
11022 };
11023 return sema.failWithOwnedErrorMsg(msg);
11024 };11056 };
11025 const field_index_u32 = @intCast(u32, field_index);11057 const field_index_u32 = @intCast(u32, field_index);
11026 var anon_decl = try block.startAnonDecl();11058 var anon_decl = try block.startAnonDecl();
...@@ -11030,14 +11062,34 @@ fn fieldPtr(...@@ -11030,14 +11062,34 @@ fn fieldPtr(
11030 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),11062 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
11031 ));11063 ));
11032 },11064 },
11065 .Struct, .Opaque => {
11066 if (child_type.getNamespace()) |namespace| {
11067 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
11068 return inst;
11069 }
11070 }
11071 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
11072 },
11033 else => return sema.fail(block, src, "type '{}' has no members", .{child_type}),11073 else => return sema.fail(block, src, "type '{}' has no members", .{child_type}),
11034 }11074 }
11035 },11075 },
11036 .Struct => return sema.structFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty),11076 .Struct => {
11037 .Union => return sema.unionFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty),11077 const inner_ptr = if (is_pointer_to)
11078 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
11079 else
11080 object_ptr;
11081 return sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty);
11082 },
11083 .Union => {
11084 const inner_ptr = if (is_pointer_to)
11085 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
11086 else
11087 object_ptr;
11088 return sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty);
11089 },
11038 else => {},11090 else => {},
11039 }11091 }
11040 return sema.fail(block, src, "type '{}' does not support field access", .{object_ty});11092 return sema.fail(block, src, "type '{}' does not support field access (fieldPtr, {}.{s})", .{ object_ty, object_ptr_ty, field_name });
11041}11093}
1104211094
11043fn fieldCallBind(11095fn fieldCallBind(
...@@ -11209,7 +11261,7 @@ fn structFieldPtr(...@@ -11209,7 +11261,7 @@ fn structFieldPtr(
11209 const struct_obj = struct_ty.castTag(.@"struct").?.data;11261 const struct_obj = struct_ty.castTag(.@"struct").?.data;
1121011262
11211 const field_index_big = struct_obj.fields.getIndex(field_name) orelse11263 const field_index_big = struct_obj.fields.getIndex(field_name) orelse
11212 return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);11264 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
11213 const field_index = @intCast(u32, field_index_big);11265 const field_index = @intCast(u32, field_index_big);
11214 const field = struct_obj.fields.values()[field_index];11266 const field = struct_obj.fields.values()[field_index];
11215 const ptr_field_ty = try Type.ptr(arena, .{11267 const ptr_field_ty = try Type.ptr(arena, .{
...@@ -11246,8 +11298,9 @@ fn structFieldVal(...@@ -11246,8 +11298,9 @@ fn structFieldVal(
11246 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);11298 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);
11247 const struct_obj = struct_ty.castTag(.@"struct").?.data;11299 const struct_obj = struct_ty.castTag(.@"struct").?.data;
1124811300
11249 const field_index = struct_obj.fields.getIndex(field_name) orelse11301 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
11250 return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);11302 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
11303 const field_index = @intCast(u32, field_index_usize);
11251 const field = struct_obj.fields.values()[field_index];11304 const field = struct_obj.fields.values()[field_index];
1125211305
11253 if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| {11306 if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| {
...@@ -11258,16 +11311,7 @@ fn structFieldVal(...@@ -11258,16 +11311,7 @@ fn structFieldVal(
11258 }11311 }
1125911312
11260 try sema.requireRuntimeBlock(block, src);11313 try sema.requireRuntimeBlock(block, src);
11261 return block.addInst(.{11314 return block.addStructFieldVal(struct_byval, field_index, field.ty);
11262 .tag = .struct_field_val,
11263 .data = .{ .ty_pl = .{
11264 .ty = try sema.addType(field.ty),
11265 .payload = try sema.addExtra(Air.StructField{
11266 .struct_operand = struct_byval,
11267 .field_index = @intCast(u32, field_index),
11268 }),
11269 } },
11270 });
11271}11315}
1127211316
11273fn unionFieldPtr(11317fn unionFieldPtr(
...@@ -11326,8 +11370,9 @@ fn unionFieldVal(...@@ -11326,8 +11370,9 @@ fn unionFieldVal(
11326 const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);11370 const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);
11327 const union_obj = union_ty.cast(Type.Payload.Union).?.data;11371 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
1132811372
11329 const field_index = union_obj.fields.getIndex(field_name) orelse11373 const field_index_big = union_obj.fields.getIndex(field_name) orelse
11330 return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name);11374 return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name);
11375 const field_index = @intCast(u32, field_index_big);
1133111376
11332 const field = union_obj.fields.values()[field_index];11377 const field = union_obj.fields.values()[field_index];
1133311378
...@@ -11340,7 +11385,7 @@ fn unionFieldVal(...@@ -11340,7 +11385,7 @@ fn unionFieldVal(
11340 }11385 }
1134111386
11342 try sema.requireRuntimeBlock(block, src);11387 try sema.requireRuntimeBlock(block, src);
11343 return sema.fail(block, src, "TODO implement runtime union field access", .{});11388 return block.addStructFieldVal(union_byval, field_index, field.ty);
11344}11389}
1134511390
11346fn elemPtr(11391fn elemPtr(
...@@ -13141,6 +13186,10 @@ pub fn resolveTypeLayout(...@@ -13141,6 +13186,10 @@ pub fn resolveTypeLayout(
13141 }13186 }
13142 union_obj.status = .have_layout;13187 union_obj.status = .have_layout;
13143 },13188 },
13189 .Array => {
13190 const elem_ty = ty.childType();
13191 return sema.resolveTypeLayout(block, src, elem_ty);
13192 },
13144 else => {},13193 else => {},
13145 }13194 }
13146}13195}
...@@ -13693,10 +13742,9 @@ fn typeHasOnePossibleValue(...@@ -13693,10 +13742,9 @@ fn typeHasOnePossibleValue(
13693 sema: *Sema,13742 sema: *Sema,
13694 block: *Block,13743 block: *Block,
13695 src: LazySrcLoc,13744 src: LazySrcLoc,
13696 starting_type: Type,13745 ty: Type,
13697) CompileError!?Value {13746) CompileError!?Value {
13698 var ty = starting_type;13747 switch (ty.tag()) {
13699 while (true) switch (ty.tag()) {
13700 .f16,13748 .f16,
13701 .f32,13749 .f32,
13702 .f64,13750 .f64,
...@@ -13790,7 +13838,7 @@ fn typeHasOnePossibleValue(...@@ -13790,7 +13838,7 @@ fn typeHasOnePossibleValue(
13790 const enum_obj = resolved_ty.castTag(.enum_numbered).?.data;13838 const enum_obj = resolved_ty.castTag(.enum_numbered).?.data;
13791 if (enum_obj.fields.count() == 1) {13839 if (enum_obj.fields.count() == 1) {
13792 if (enum_obj.values.count() == 0) {13840 if (enum_obj.values.count() == 0) {
13793 return Value.initTag(.zero); // auto-numbered13841 return Value.zero; // auto-numbered
13794 } else {13842 } else {
13795 return enum_obj.values.keys()[0];13843 return enum_obj.values.keys()[0];
13796 }13844 }
...@@ -13803,7 +13851,7 @@ fn typeHasOnePossibleValue(...@@ -13803,7 +13851,7 @@ fn typeHasOnePossibleValue(
13803 const enum_obj = resolved_ty.castTag(.enum_full).?.data;13851 const enum_obj = resolved_ty.castTag(.enum_full).?.data;
13804 if (enum_obj.fields.count() == 1) {13852 if (enum_obj.fields.count() == 1) {
13805 if (enum_obj.values.count() == 0) {13853 if (enum_obj.values.count() == 0) {
13806 return Value.initTag(.zero); // auto-numbered13854 return Value.zero; // auto-numbered
13807 } else {13855 } else {
13808 return enum_obj.values.keys()[0];13856 return enum_obj.values.keys()[0];
13809 }13857 }
...@@ -13815,12 +13863,19 @@ fn typeHasOnePossibleValue(...@@ -13815,12 +13863,19 @@ fn typeHasOnePossibleValue(
13815 const resolved_ty = try sema.resolveTypeFields(block, src, ty);13863 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
13816 const enum_simple = resolved_ty.castTag(.enum_simple).?.data;13864 const enum_simple = resolved_ty.castTag(.enum_simple).?.data;
13817 if (enum_simple.fields.count() == 1) {13865 if (enum_simple.fields.count() == 1) {
13818 return Value.initTag(.zero);13866 return Value.zero;
13867 } else {
13868 return null;
13869 }
13870 },
13871 .enum_nonexhaustive => {
13872 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
13873 if (!tag_ty.hasCodeGenBits()) {
13874 return Value.zero;
13819 } else {13875 } else {
13820 return null;13876 return null;
13821 }13877 }
13822 },13878 },
13823 .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty,
13824 .@"union" => {13879 .@"union" => {
13825 return null; // TODO13880 return null; // TODO
13826 },13881 },
...@@ -13836,7 +13891,7 @@ fn typeHasOnePossibleValue(...@@ -13836,7 +13891,7 @@ fn typeHasOnePossibleValue(
1383613891
13837 .int_unsigned, .int_signed => {13892 .int_unsigned, .int_signed => {
13838 if (ty.cast(Type.Payload.Bits).?.data == 0) {13893 if (ty.cast(Type.Payload.Bits).?.data == 0) {
13839 return Value.initTag(.zero);13894 return Value.zero;
13840 } else {13895 } else {
13841 return null;13896 return null;
13842 }13897 }
...@@ -13844,14 +13899,16 @@ fn typeHasOnePossibleValue(...@@ -13844,14 +13899,16 @@ fn typeHasOnePossibleValue(
13844 .vector, .array, .array_u8 => {13899 .vector, .array, .array_u8 => {
13845 if (ty.arrayLen() == 0)13900 if (ty.arrayLen() == 0)
13846 return Value.initTag(.empty_array);13901 return Value.initTag(.empty_array);
13847 ty = ty.elemType();13902 if ((try sema.typeHasOnePossibleValue(block, src, ty.elemType())) != null) {
13848 continue;13903 return Value.initTag(.the_only_possible_value);
13904 }
13905 return null;
13849 },13906 },
1385013907
13851 .inferred_alloc_const => unreachable,13908 .inferred_alloc_const => unreachable,
13852 .inferred_alloc_mut => unreachable,13909 .inferred_alloc_mut => unreachable,
13853 .generic_poison => return error.GenericPoison,13910 .generic_poison => return error.GenericPoison,
13854 };13911 }
13855}13912}
1385613913
13857fn getAstTree(sema: *Sema, block: *Block) CompileError!*const std.zig.Ast {13914fn getAstTree(sema: *Sema, block: *Block) CompileError!*const std.zig.Ast {
src/arch/aarch64/CodeGen.zig+15
...@@ -494,6 +494,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -494,6 +494,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
494 .slice_ptr => try self.airSlicePtr(inst),494 .slice_ptr => try self.airSlicePtr(inst),
495 .slice_len => try self.airSliceLen(inst),495 .slice_len => try self.airSliceLen(inst),
496496
497 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
498 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
499
497 .array_elem_val => try self.airArrayElemVal(inst),500 .array_elem_val => try self.airArrayElemVal(inst),
498 .slice_elem_val => try self.airSliceElemVal(inst),501 .slice_elem_val => try self.airSliceElemVal(inst),
499 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),502 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),
...@@ -1057,6 +1060,18 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -1057,6 +1060,18 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
1057 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1060 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1058}1061}
10591062
1063fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
1064 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1065 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_slice_len_ptr for {}", .{self.target.cpu.arch});
1066 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1067}
1068
1069fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
1070 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1071 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{self.target.cpu.arch});
1072 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1073}
1074
1060fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {1075fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1061 const is_volatile = false; // TODO1076 const is_volatile = false; // TODO
1062 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1077 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
src/codegen.zig+19
...@@ -842,6 +842,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -842,6 +842,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
842 .slice_ptr => try self.airSlicePtr(inst),842 .slice_ptr => try self.airSlicePtr(inst),
843 .slice_len => try self.airSliceLen(inst),843 .slice_len => try self.airSliceLen(inst),
844844
845 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
846 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
847
845 .array_elem_val => try self.airArrayElemVal(inst),848 .array_elem_val => try self.airArrayElemVal(inst),
846 .slice_elem_val => try self.airSliceElemVal(inst),849 .slice_elem_val => try self.airSliceElemVal(inst),
847 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),850 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),
...@@ -1498,6 +1501,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1498,6 +1501,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1498 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1501 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1499 }1502 }
15001503
1504 fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
1505 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1506 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1507 else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{self.target.cpu.arch}),
1508 };
1509 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1510 }
1511
1512 fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
1513 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1514 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1515 else => return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{self.target.cpu.arch}),
1516 };
1517 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1518 }
1519
1501 fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {1520 fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1502 const is_volatile = false; // TODO1521 const is_volatile = false; // TODO
1503 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1522 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
src/codegen/c.zig+18
...@@ -1075,6 +1075,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1075,6 +1075,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1075 .slice_ptr => try airSliceField(f, inst, ".ptr;\n"),1075 .slice_ptr => try airSliceField(f, inst, ".ptr;\n"),
1076 .slice_len => try airSliceField(f, inst, ".len;\n"),1076 .slice_len => try airSliceField(f, inst, ".len;\n"),
10771077
1078 .ptr_slice_len_ptr => try airPtrSliceFieldPtr(f, inst, ".len;\n"),
1079 .ptr_slice_ptr_ptr => try airPtrSliceFieldPtr(f, inst, ".ptr;\n"),
1080
1078 .ptr_elem_val => try airPtrElemVal(f, inst, "["),1081 .ptr_elem_val => try airPtrElemVal(f, inst, "["),
1079 .ptr_ptr_elem_val => try airPtrElemVal(f, inst, "[0]["),1082 .ptr_ptr_elem_val => try airPtrElemVal(f, inst, "[0]["),
1080 .ptr_elem_ptr => try airPtrElemPtr(f, inst),1083 .ptr_elem_ptr => try airPtrElemPtr(f, inst),
...@@ -1114,6 +1117,21 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue...@@ -1114,6 +1117,21 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue
1114 return local;1117 return local;
1115}1118}
11161119
1120fn airPtrSliceFieldPtr(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue {
1121 if (f.liveness.isUnused(inst))
1122 return CValue.none;
1123
1124 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1125 const operand = try f.resolveInst(ty_op.operand);
1126 const writer = f.object.writer();
1127
1128 _ = writer;
1129 _ = operand;
1130 _ = suffix;
1131
1132 return f.fail("TODO: C backend: airPtrSliceFieldPtr", .{});
1133}
1134
1117fn airPtrElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue {1135fn airPtrElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue {
1118 const is_volatile = false; // TODO1136 const is_volatile = false; // TODO
1119 if (!is_volatile and f.liveness.isUnused(inst))1137 if (!is_volatile and f.liveness.isUnused(inst))
src/codegen/llvm.zig+44-10
...@@ -1261,6 +1261,10 @@ pub const DeclGen = struct {...@@ -1261,6 +1261,10 @@ pub const DeclGen = struct {
1261 }1261 }
1262 const field_ty = tv.ty.unionFieldType(tag_and_val.tag);1262 const field_ty = tv.ty.unionFieldType(tag_and_val.tag);
1263 const payload = p: {1263 const payload = p: {
1264 if (!field_ty.hasCodeGenBits()) {
1265 const padding_len = @intCast(c_uint, layout.payload_size);
1266 break :p self.context.intType(8).arrayType(padding_len).getUndef();
1267 }
1264 const field = try genTypedValue(self, .{ .ty = field_ty, .val = tag_and_val.val });1268 const field = try genTypedValue(self, .{ .ty = field_ty, .val = tag_and_val.val });
1265 const field_size = field_ty.abiSize(target);1269 const field_size = field_ty.abiSize(target);
1266 if (field_size == layout.payload_size) {1270 if (field_size == layout.payload_size) {
...@@ -1709,6 +1713,10 @@ pub const FuncGen = struct {...@@ -1709,6 +1713,10 @@ pub const FuncGen = struct {
1709 .assembly => try self.airAssembly(inst),1713 .assembly => try self.airAssembly(inst),
1710 .slice_ptr => try self.airSliceField(inst, 0),1714 .slice_ptr => try self.airSliceField(inst, 0),
1711 .slice_len => try self.airSliceField(inst, 1),1715 .slice_len => try self.airSliceField(inst, 1),
1716
1717 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
1718 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
1719
1712 .array_to_slice => try self.airArrayToSlice(inst),1720 .array_to_slice => try self.airArrayToSlice(inst),
1713 .float_to_int => try self.airFloatToInt(inst),1721 .float_to_int => try self.airFloatToInt(inst),
1714 .int_to_float => try self.airIntToFloat(inst),1722 .int_to_float => try self.airIntToFloat(inst),
...@@ -2091,6 +2099,15 @@ pub const FuncGen = struct {...@@ -2091,6 +2099,15 @@ pub const FuncGen = struct {
2091 return self.builder.buildExtractValue(operand, index, "");2099 return self.builder.buildExtractValue(operand, index, "");
2092 }2100 }
20932101
2102 fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value {
2103 if (self.liveness.isUnused(inst)) return null;
2104
2105 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2106 const slice_ptr = try self.resolveInst(ty_op.operand);
2107
2108 return self.builder.buildStructGEP(slice_ptr, index, "");
2109 }
2110
2094 fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {2111 fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
2095 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2112 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2096 const slice_ty = self.air.typeOf(bin_op.lhs);2113 const slice_ty = self.air.typeOf(bin_op.lhs);
...@@ -2223,17 +2240,34 @@ pub const FuncGen = struct {...@@ -2223,17 +2240,34 @@ pub const FuncGen = struct {
2223 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;2240 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
2224 const struct_ty = self.air.typeOf(struct_field.struct_operand);2241 const struct_ty = self.air.typeOf(struct_field.struct_operand);
2225 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);2242 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);
2226 const field_index = llvmFieldIndex(struct_ty, struct_field.field_index);2243 const field_index = struct_field.field_index;
2227 if (isByRef(struct_ty)) {2244 const field_ty = struct_ty.structFieldType(field_index);
2228 const field_ptr = self.builder.buildStructGEP(struct_llvm_val, field_index, "");2245 if (!field_ty.hasCodeGenBits()) {
2229 const field_ty = struct_ty.structFieldType(struct_field.field_index);2246 return null;
2230 if (isByRef(field_ty)) {2247 }
2231 return field_ptr;2248
2232 } else {2249 assert(isByRef(struct_ty));
2233 return self.builder.buildLoad(field_ptr, "");2250
2234 }2251 const field_ptr = switch (struct_ty.zigTypeTag()) {
2252 .Struct => blk: {
2253 const llvm_field_index = llvmFieldIndex(struct_ty, field_index);
2254 break :blk self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, "");
2255 },
2256 .Union => blk: {
2257 const llvm_field_ty = try self.dg.llvmType(field_ty);
2258 const target = self.dg.module.getTarget();
2259 const layout = struct_ty.unionGetLayout(target);
2260 const payload_index = @boolToInt(layout.tag_align >= layout.payload_align);
2261 const union_field_ptr = self.builder.buildStructGEP(struct_llvm_val, payload_index, "");
2262 break :blk self.builder.buildBitCast(union_field_ptr, llvm_field_ty.pointerType(0), "");
2263 },
2264 else => unreachable,
2265 };
2266
2267 if (isByRef(field_ty)) {
2268 return field_ptr;
2235 } else {2269 } else {
2236 return self.builder.buildExtractValue(struct_llvm_val, field_index, "");2270 return self.builder.buildLoad(field_ptr, "");
2237 }2271 }
2238 }2272 }
22392273
src/codegen/wasm.zig+10
...@@ -866,6 +866,7 @@ pub const Context = struct {...@@ -866,6 +866,7 @@ pub const Context = struct {
866 .struct_field_ptr_index_1 => self.airStructFieldPtrIndex(inst, 1),866 .struct_field_ptr_index_1 => self.airStructFieldPtrIndex(inst, 1),
867 .struct_field_ptr_index_2 => self.airStructFieldPtrIndex(inst, 2),867 .struct_field_ptr_index_2 => self.airStructFieldPtrIndex(inst, 2),
868 .struct_field_ptr_index_3 => self.airStructFieldPtrIndex(inst, 3),868 .struct_field_ptr_index_3 => self.airStructFieldPtrIndex(inst, 3),
869 .struct_field_val => self.airStructFieldVal(inst),
869 .switch_br => self.airSwitchBr(inst),870 .switch_br => self.airSwitchBr(inst),
870 .unreach => self.airUnreachable(inst),871 .unreach => self.airUnreachable(inst),
871 .wrap_optional => self.airWrapOptional(inst),872 .wrap_optional => self.airWrapOptional(inst),
...@@ -1456,6 +1457,15 @@ pub const Context = struct {...@@ -1456,6 +1457,15 @@ pub const Context = struct {
1456 return WValue{ .local = struct_ptr.multi_value.index + index };1457 return WValue{ .local = struct_ptr.multi_value.index + index };
1457 }1458 }
14581459
1460 fn airStructFieldVal(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
1461 if (self.liveness.isUnused(inst)) return WValue.none;
1462
1463 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1464 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
1465 const struct_multivalue = self.resolveInst(extra.struct_operand).multi_value;
1466 return WValue{ .local = struct_multivalue.index + extra.field_index };
1467 }
1468
1459 fn airSwitchBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {1469 fn airSwitchBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
1460 // result type is always 'noreturn'1470 // result type is always 'noreturn'
1461 const blocktype = wasm.block_empty;1471 const blocktype = wasm.block_empty;
src/print_air.zig+2
...@@ -183,6 +183,8 @@ const Writer = struct {...@@ -183,6 +183,8 @@ const Writer = struct {
183 .wrap_errunion_err,183 .wrap_errunion_err,
184 .slice_ptr,184 .slice_ptr,
185 .slice_len,185 .slice_len,
186 .ptr_slice_len_ptr,
187 .ptr_slice_ptr_ptr,
186 .struct_field_ptr_index_0,188 .struct_field_ptr_index_0,
187 .struct_field_ptr_index_1,189 .struct_field_ptr_index_1,
188 .struct_field_ptr_index_2,190 .struct_field_ptr_index_2,
src/type.zig+24-9
...@@ -2676,7 +2676,7 @@ pub const Type = extern union {...@@ -2676,7 +2676,7 @@ pub const Type = extern union {
26762676
2677 .pointer => return self.castTag(.pointer).?.data.sentinel,2677 .pointer => return self.castTag(.pointer).?.data.sentinel,
2678 .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel,2678 .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel,
2679 .array_u8_sentinel_0 => return Value.initTag(.zero),2679 .array_u8_sentinel_0 => return Value.zero,
26802680
2681 else => unreachable,2681 else => unreachable,
2682 };2682 };
...@@ -3096,6 +3096,14 @@ pub const Type = extern union {...@@ -3096,6 +3096,14 @@ pub const Type = extern union {
3096 }3096 }
3097 return Value.initTag(.empty_struct_value);3097 return Value.initTag(.empty_struct_value);
3098 },3098 },
3099 .enum_numbered => {
3100 const enum_numbered = ty.castTag(.enum_numbered).?.data;
3101 if (enum_numbered.fields.count() == 1) {
3102 return enum_numbered.values.keys()[0];
3103 } else {
3104 return null;
3105 }
3106 },
3099 .enum_full => {3107 .enum_full => {
3100 const enum_full = ty.castTag(.enum_full).?.data;3108 const enum_full = ty.castTag(.enum_full).?.data;
3101 if (enum_full.fields.count() == 1) {3109 if (enum_full.fields.count() == 1) {
...@@ -3107,13 +3115,19 @@ pub const Type = extern union {...@@ -3107,13 +3115,19 @@ pub const Type = extern union {
3107 .enum_simple => {3115 .enum_simple => {
3108 const enum_simple = ty.castTag(.enum_simple).?.data;3116 const enum_simple = ty.castTag(.enum_simple).?.data;
3109 if (enum_simple.fields.count() == 1) {3117 if (enum_simple.fields.count() == 1) {
3110 return Value.initTag(.zero);3118 return Value.zero;
3119 } else {
3120 return null;
3121 }
3122 },
3123 .enum_nonexhaustive => {
3124 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
3125 if (!tag_ty.hasCodeGenBits()) {
3126 return Value.zero;
3111 } else {3127 } else {
3112 return null;3128 return null;
3113 }3129 }
3114 },3130 },
3115 .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty,
3116 .enum_numbered => ty = ty.castTag(.enum_numbered).?.data.tag_ty,
3117 .@"union" => {3131 .@"union" => {
3118 return null; // TODO3132 return null; // TODO
3119 },3133 },
...@@ -3129,7 +3143,7 @@ pub const Type = extern union {...@@ -3129,7 +3143,7 @@ pub const Type = extern union {
31293143
3130 .int_unsigned, .int_signed => {3144 .int_unsigned, .int_signed => {
3131 if (ty.cast(Payload.Bits).?.data == 0) {3145 if (ty.cast(Payload.Bits).?.data == 0) {
3132 return Value.initTag(.zero);3146 return Value.zero;
3133 } else {3147 } else {
3134 return null;3148 return null;
3135 }3149 }
...@@ -3137,8 +3151,9 @@ pub const Type = extern union {...@@ -3137,8 +3151,9 @@ pub const Type = extern union {
3137 .vector, .array, .array_u8 => {3151 .vector, .array, .array_u8 => {
3138 if (ty.arrayLen() == 0)3152 if (ty.arrayLen() == 0)
3139 return Value.initTag(.empty_array);3153 return Value.initTag(.empty_array);
3140 ty = ty.elemType();3154 if (ty.elemType().onePossibleValue() != null)
3141 continue;3155 return Value.initTag(.the_only_possible_value);
3156 return null;
3142 },3157 },
31433158
3144 .inferred_alloc_const => unreachable,3159 .inferred_alloc_const => unreachable,
...@@ -3179,7 +3194,7 @@ pub const Type = extern union {...@@ -3179,7 +3194,7 @@ pub const Type = extern union {
3179 const info = self.intInfo(target);3194 const info = self.intInfo(target);
31803195
3181 if (info.signedness == .unsigned) {3196 if (info.signedness == .unsigned) {
3182 return Value.initTag(.zero);3197 return Value.zero;
3183 }3198 }
31843199
3185 if (info.bits <= 6) {3200 if (info.bits <= 6) {
...@@ -4013,7 +4028,7 @@ pub const Type = extern union {...@@ -4013,7 +4028,7 @@ pub const Type = extern union {
4013 ) Allocator.Error!Type {4028 ) Allocator.Error!Type {
4014 if (elem_type.eql(Type.u8)) {4029 if (elem_type.eql(Type.u8)) {
4015 if (sent) |some| {4030 if (sent) |some| {
4016 if (some.eql(Value.initTag(.zero), elem_type)) {4031 if (some.eql(Value.zero, elem_type)) {
4017 return Tag.array_u8_sentinel_0.create(arena, len);4032 return Tag.array_u8_sentinel_0.create(arena, len);
4018 }4033 }
4019 } else {4034 } else {
src/value.zig+74-37
...@@ -86,6 +86,8 @@ pub const Value = extern union {...@@ -86,6 +86,8 @@ pub const Value = extern union {
86 one,86 one,
87 void_value,87 void_value,
88 unreachable_value,88 unreachable_value,
89 /// The only possible value for a particular type, which is stored externally.
90 the_only_possible_value,
89 null_value,91 null_value,
90 bool_true,92 bool_true,
91 bool_false,93 bool_false,
...@@ -226,6 +228,7 @@ pub const Value = extern union {...@@ -226,6 +228,7 @@ pub const Value = extern union {
226 .one,228 .one,
227 .void_value,229 .void_value,
228 .unreachable_value,230 .unreachable_value,
231 .the_only_possible_value,
229 .empty_struct_value,232 .empty_struct_value,
230 .empty_array,233 .empty_array,
231 .null_value,234 .null_value,
...@@ -415,6 +418,7 @@ pub const Value = extern union {...@@ -415,6 +418,7 @@ pub const Value = extern union {
415 .one,418 .one,
416 .void_value,419 .void_value,
417 .unreachable_value,420 .unreachable_value,
421 .the_only_possible_value,
418 .empty_array,422 .empty_array,
419 .null_value,423 .null_value,
420 .bool_true,424 .bool_true,
...@@ -664,6 +668,7 @@ pub const Value = extern union {...@@ -664,6 +668,7 @@ pub const Value = extern union {
664 .one => return out_stream.writeAll("1"),668 .one => return out_stream.writeAll("1"),
665 .void_value => return out_stream.writeAll("{}"),669 .void_value => return out_stream.writeAll("{}"),
666 .unreachable_value => return out_stream.writeAll("unreachable"),670 .unreachable_value => return out_stream.writeAll("unreachable"),
671 .the_only_possible_value => return out_stream.writeAll("(the only possible value)"),
667 .bool_true => return out_stream.writeAll("true"),672 .bool_true => return out_stream.writeAll("true"),
668 .bool_false => return out_stream.writeAll("false"),673 .bool_false => return out_stream.writeAll("false"),
669 .ty => return val.castTag(.ty).?.data.format("", options, out_stream),674 .ty => return val.castTag(.ty).?.data.format("", options, out_stream),
...@@ -755,6 +760,7 @@ pub const Value = extern union {...@@ -755,6 +760,7 @@ pub const Value = extern union {
755 const decl_val = try decl.value();760 const decl_val = try decl.value();
756 return decl_val.toAllocatedBytes(decl.ty, allocator);761 return decl_val.toAllocatedBytes(decl.ty, allocator);
757 },762 },
763 .the_only_possible_value => return &[_]u8{},
758 else => unreachable,764 else => unreachable,
759 }765 }
760 }766 }
...@@ -847,53 +853,63 @@ pub const Value = extern union {...@@ -847,53 +853,63 @@ pub const Value = extern union {
847 // TODO should `@intToEnum` do this `@intCast` for you?853 // TODO should `@intToEnum` do this `@intCast` for you?
848 return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));854 return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));
849 },855 },
856 .the_only_possible_value => {
857 const fields = std.meta.fields(E);
858 assert(fields.len == 1);
859 return @intToEnum(E, fields[0].value);
860 },
850 else => unreachable,861 else => unreachable,
851 }862 }
852 }863 }
853864
854 pub fn enumToInt(val: Value, ty: Type, buffer: *Payload.U64) Value {865 pub fn enumToInt(val: Value, ty: Type, buffer: *Payload.U64) Value {
855 if (val.castTag(.enum_field_index)) |enum_field_payload| {866 const field_index = switch (val.tag()) {
856 const field_index = enum_field_payload.data;867 .enum_field_index => val.castTag(.enum_field_index).?.data,
857 switch (ty.tag()) {868 .the_only_possible_value => blk: {
858 .enum_full, .enum_nonexhaustive => {869 assert(ty.enumFieldCount() == 1);
859 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;870 break :blk 0;
860 if (enum_full.values.count() != 0) {871 },
861 return enum_full.values.keys()[field_index];872 // Assume it is already an integer and return it directly.
862 } else {873 else => return val,
863 // Field index and integer values are the same.874 };
864 buffer.* = .{875
865 .base = .{ .tag = .int_u64 },876 switch (ty.tag()) {
866 .data = field_index,877 .enum_full, .enum_nonexhaustive => {
867 };878 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
868 return Value.initPayload(&buffer.base);879 if (enum_full.values.count() != 0) {
869 }880 return enum_full.values.keys()[field_index];
870 },881 } else {
871 .enum_numbered => {
872 const enum_obj = ty.castTag(.enum_numbered).?.data;
873 if (enum_obj.values.count() != 0) {
874 return enum_obj.values.keys()[field_index];
875 } else {
876 // Field index and integer values are the same.
877 buffer.* = .{
878 .base = .{ .tag = .int_u64 },
879 .data = field_index,
880 };
881 return Value.initPayload(&buffer.base);
882 }
883 },
884 .enum_simple => {
885 // Field index and integer values are the same.882 // Field index and integer values are the same.
886 buffer.* = .{883 buffer.* = .{
887 .base = .{ .tag = .int_u64 },884 .base = .{ .tag = .int_u64 },
888 .data = field_index,885 .data = field_index,
889 };886 };
890 return Value.initPayload(&buffer.base);887 return Value.initPayload(&buffer.base);
891 },888 }
892 else => unreachable,889 },
893 }890 .enum_numbered => {
891 const enum_obj = ty.castTag(.enum_numbered).?.data;
892 if (enum_obj.values.count() != 0) {
893 return enum_obj.values.keys()[field_index];
894 } else {
895 // Field index and integer values are the same.
896 buffer.* = .{
897 .base = .{ .tag = .int_u64 },
898 .data = field_index,
899 };
900 return Value.initPayload(&buffer.base);
901 }
902 },
903 .enum_simple => {
904 // Field index and integer values are the same.
905 buffer.* = .{
906 .base = .{ .tag = .int_u64 },
907 .data = field_index,
908 };
909 return Value.initPayload(&buffer.base);
910 },
911 else => unreachable,
894 }912 }
895 // Assume it is already an integer and return it directly.
896 return val;
897 }913 }
898914
899 /// Asserts the value is an integer.915 /// Asserts the value is an integer.
...@@ -901,6 +917,7 @@ pub const Value = extern union {...@@ -901,6 +917,7 @@ pub const Value = extern union {
901 switch (self.tag()) {917 switch (self.tag()) {
902 .zero,918 .zero,
903 .bool_false,919 .bool_false,
920 .the_only_possible_value, // i0, u0
904 => return BigIntMutable.init(&space.limbs, 0).toConst(),921 => return BigIntMutable.init(&space.limbs, 0).toConst(),
905922
906 .one,923 .one,
...@@ -922,6 +939,7 @@ pub const Value = extern union {...@@ -922,6 +939,7 @@ pub const Value = extern union {
922 switch (self.tag()) {939 switch (self.tag()) {
923 .zero,940 .zero,
924 .bool_false,941 .bool_false,
942 .the_only_possible_value, // i0, u0
925 => return 0,943 => return 0,
926944
927 .one,945 .one,
...@@ -943,6 +961,7 @@ pub const Value = extern union {...@@ -943,6 +961,7 @@ pub const Value = extern union {
943 switch (self.tag()) {961 switch (self.tag()) {
944 .zero,962 .zero,
945 .bool_false,963 .bool_false,
964 .the_only_possible_value, // i0, u0
946 => return 0,965 => return 0,
947966
948 .one,967 .one,
...@@ -1124,6 +1143,11 @@ pub const Value = extern union {...@@ -1124,6 +1143,11 @@ pub const Value = extern union {
1124 @panic("TODO implement int_big_negative Value clz");1143 @panic("TODO implement int_big_negative Value clz");
1125 },1144 },
11261145
1146 .the_only_possible_value => {
1147 assert(ty_bits == 0);
1148 return ty_bits;
1149 },
1150
1127 else => unreachable,1151 else => unreachable,
1128 }1152 }
1129 }1153 }
...@@ -1134,6 +1158,7 @@ pub const Value = extern union {...@@ -1134,6 +1158,7 @@ pub const Value = extern union {
1134 switch (self.tag()) {1158 switch (self.tag()) {
1135 .zero,1159 .zero,
1136 .bool_false,1160 .bool_false,
1161 .the_only_possible_value,
1137 => return 0,1162 => return 0,
11381163
1139 .one,1164 .one,
...@@ -1213,6 +1238,11 @@ pub const Value = extern union {...@@ -1213,6 +1238,11 @@ pub const Value = extern union {
1213 else => unreachable,1238 else => unreachable,
1214 },1239 },
12151240
1241 .the_only_possible_value => {
1242 assert(ty.intInfo(target).bits == 0);
1243 return true;
1244 },
1245
1216 else => unreachable,1246 else => unreachable,
1217 }1247 }
1218 }1248 }
...@@ -1251,7 +1281,7 @@ pub const Value = extern union {...@@ -1251,7 +1281,7 @@ pub const Value = extern union {
1251 /// Asserts the value is numeric1281 /// Asserts the value is numeric
1252 pub fn isZero(self: Value) bool {1282 pub fn isZero(self: Value) bool {
1253 return switch (self.tag()) {1283 return switch (self.tag()) {
1254 .zero => true,1284 .zero, .the_only_possible_value => true,
1255 .one => false,1285 .one => false,
12561286
1257 .int_u64 => self.castTag(.int_u64).?.data == 0,1287 .int_u64 => self.castTag(.int_u64).?.data == 0,
...@@ -1272,6 +1302,7 @@ pub const Value = extern union {...@@ -1272,6 +1302,7 @@ pub const Value = extern union {
1272 return switch (lhs.tag()) {1302 return switch (lhs.tag()) {
1273 .zero,1303 .zero,
1274 .bool_false,1304 .bool_false,
1305 .the_only_possible_value,
1275 => .eq,1306 => .eq,
12761307
1277 .one,1308 .one,
...@@ -1354,7 +1385,7 @@ pub const Value = extern union {...@@ -1354,7 +1385,7 @@ pub const Value = extern union {
1354 assert(b_tag != .undef);1385 assert(b_tag != .undef);
1355 if (a_tag == b_tag) {1386 if (a_tag == b_tag) {
1356 switch (a_tag) {1387 switch (a_tag) {
1357 .void_value, .null_value => return true,1388 .void_value, .null_value, .the_only_possible_value => return true,
1358 .enum_literal => {1389 .enum_literal => {
1359 const a_name = a.castTag(.enum_literal).?.data;1390 const a_name = a.castTag(.enum_literal).?.data;
1360 const b_name = b.castTag(.enum_literal).?.data;1391 const b_name = b.castTag(.enum_literal).?.data;
...@@ -1706,6 +1737,9 @@ pub const Value = extern union {...@@ -1706,6 +1737,9 @@ pub const Value = extern union {
1706 .decl_ref => return val.castTag(.decl_ref).?.data.val.elemValueAdvanced(index, arena, buffer),1737 .decl_ref => return val.castTag(.decl_ref).?.data.val.elemValueAdvanced(index, arena, buffer),
1707 .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.val.elemValueAdvanced(index, arena, buffer),1738 .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.val.elemValueAdvanced(index, arena, buffer),
17081739
1740 // The child type of arrays which have only one possible value need to have only one possible value itself.
1741 .the_only_possible_value => return val,
1742
1709 else => unreachable,1743 else => unreachable,
1710 }1744 }
1711 }1745 }
...@@ -1722,6 +1756,8 @@ pub const Value = extern union {...@@ -1722,6 +1756,8 @@ pub const Value = extern union {
1722 // TODO assert the tag is correct1756 // TODO assert the tag is correct
1723 return payload.val;1757 return payload.val;
1724 },1758 },
1759 // Structs which have only one possible value need to consist of members which have only one possible value.
1760 .the_only_possible_value => return val,
17251761
1726 else => unreachable,1762 else => unreachable,
1727 }1763 }
...@@ -1820,6 +1856,7 @@ pub const Value = extern union {...@@ -1820,6 +1856,7 @@ pub const Value = extern union {
1820 pub fn intToFloat(val: Value, allocator: *Allocator, dest_ty: Type, target: Target) !Value {1856 pub fn intToFloat(val: Value, allocator: *Allocator, dest_ty: Type, target: Target) !Value {
1821 switch (val.tag()) {1857 switch (val.tag()) {
1822 .undef, .zero, .one => return val,1858 .undef, .zero, .one => return val,
1859 .the_only_possible_value => return Value.initTag(.zero), // for i0, u0
1823 .int_u64 => {1860 .int_u64 => {
1824 return intToFloatInner(val.castTag(.int_u64).?.data, allocator, dest_ty, target);1861 return intToFloatInner(val.castTag(.int_u64).?.data, allocator, dest_ty, target);
1825 },1862 },