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 {
367367 /// Given a slice value, return the pointer.
368368 /// Uses the `ty_op` field.
369369 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,
370376 /// Given an array value and element index, return the element value at that index.
371377 /// Result type is the element type of the array operand.
372378 /// Uses the `bin_op` field.
......@@ -707,6 +713,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
707713 .wrap_errunion_payload,
708714 .wrap_errunion_err,
709715 .slice_ptr,
716 .ptr_slice_len_ptr,
717 .ptr_slice_ptr_ptr,
710718 .struct_field_ptr_index_0,
711719 .struct_field_ptr_index_1,
712720 .struct_field_ptr_index_2,
src/AstGen.zig+16-21
......@@ -193,9 +193,6 @@ pub const ResultLoc = union(enum) {
193193 /// The expression must generate a pointer rather than a value. For example, the left hand side
194194 /// of an assignment uses this kind of result location.
195195 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,
199196 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.
200197 ty: Zir.Inst.Ref,
201198 /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion,
......@@ -231,7 +228,7 @@ pub const ResultLoc = union(enum) {
231228 fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy {
232229 switch (rl) {
233230 // 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 .{
235232 .tag = .break_operand,
236233 .elide_store_to_block_ptr_instructions = false,
237234 },
......@@ -727,7 +724,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
727724 .start = start,
728725 });
729726 switch (rl) {
730 .ref, .none_or_ref => return result,
727 .ref => return result,
731728 else => {
732729 const dereffed = try gz.addUnNode(.load, result, node);
733730 return rvalue(gz, rl, dereffed, node);
......@@ -745,7 +742,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
745742 .end = end,
746743 });
747744 switch (rl) {
748 .ref, .none_or_ref => return result,
745 .ref => return result,
749746 else => {
750747 const dereffed = try gz.addUnNode(.load, result, node);
751748 return rvalue(gz, rl, dereffed, node);
......@@ -765,7 +762,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
765762 .sentinel = sentinel,
766763 });
767764 switch (rl) {
768 .ref, .none_or_ref => return result,
765 .ref => return result,
769766 else => {
770767 const dereffed = try gz.addUnNode(.load, result, node);
771768 return rvalue(gz, rl, dereffed, node);
......@@ -776,7 +773,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
776773 .deref => {
777774 const lhs = try expr(gz, scope, .none, node_datas[node].lhs);
778775 switch (rl) {
779 .ref, .none_or_ref => return lhs,
776 .ref => return lhs,
780777 else => {
781778 const result = try gz.addUnNode(.load, lhs, node);
782779 return rvalue(gz, rl, result, node);
......@@ -1273,7 +1270,7 @@ fn arrayInitExpr(
12731270 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref);
12741271 }
12751272 },
1276 .none, .none_or_ref => {
1273 .none => {
12771274 if (types.array != .none) {
12781275 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);
12791276 } else {
......@@ -1475,7 +1472,7 @@ fn structInitExpr(
14751472 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref);
14761473 }
14771474 },
1478 .none, .none_or_ref => {
1475 .none => {
14791476 if (struct_init.ast.type_expr != 0) {
14801477 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
14811478 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
......@@ -5133,7 +5130,7 @@ fn fieldAccess(
51335130 if (rl == .ref) {
51345131 return addFieldAccess(.field_ptr, gz, scope, .ref, node);
51355132 } 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);
51375134 return rvalue(gz, rl, access, node);
51385135 }
51395136}
......@@ -5178,7 +5175,7 @@ fn arrayAccess(
51785175 ),
51795176 else => return rvalue(gz, rl, try gz.addBin(
51805177 .elem_val,
5181 try expr(gz, scope, .none_or_ref, node_datas[node].lhs),
5178 try expr(gz, scope, .none, node_datas[node].lhs),
51825179 try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),
51835180 ), node),
51845181 }
......@@ -6664,7 +6661,7 @@ fn identifier(
66646661 );
66656662
66666663 switch (rl) {
6667 .ref, .none_or_ref => return ptr_inst,
6664 .ref => return ptr_inst,
66686665 else => {
66696666 const loaded = try gz.addUnNode(.load, ptr_inst, ident);
66706667 return rvalue(gz, rl, loaded, ident);
......@@ -6700,7 +6697,7 @@ fn identifier(
67006697 // Decl references happen by name rather than ZIR index so that when unrelated
67016698 // decls are modified, ZIR code containing references to them can be unmodified.
67026699 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),
67046701 else => {
67056702 const result = try gz.addStrTok(.decl_val, name_str_index, ident_token);
67066703 return rvalue(gz, rl, result, ident);
......@@ -7105,7 +7102,7 @@ fn as(
71057102) InnerError!Zir.Inst.Ref {
71067103 const dest_type = try typeExpr(gz, scope, lhs);
71077104 switch (rl) {
7108 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty => {
7105 .none, .discard, .ref, .ty, .coerced_ty => {
71097106 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);
71107107 return rvalue(gz, rl, result, node);
71117108 },
......@@ -7128,7 +7125,7 @@ fn unionInit(
71287125 const union_type = try typeExpr(gz, scope, params[0]);
71297126 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
71307127 switch (rl) {
7131 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => {
7128 .none, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => {
71327129 _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{
71337130 .container_type = union_type,
71347131 .field_name = field_name,
......@@ -7192,7 +7189,7 @@ fn bitCast(
71927189 const astgen = gz.astgen;
71937190 const dest_type = try typeExpr(gz, scope, lhs);
71947191 switch (rl) {
7195 .none, .none_or_ref, .discard, .ty, .coerced_ty => {
7192 .none, .discard, .ty, .coerced_ty => {
71967193 const operand = try expr(gz, scope, .none, rhs);
71977194 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{
71987195 .lhs = dest_type,
......@@ -8799,7 +8796,7 @@ fn rvalue(
87998796) InnerError!Zir.Inst.Ref {
88008797 if (gz.endsWithNoReturn()) return result;
88018798 switch (rl) {
8802 .none, .none_or_ref, .coerced_ty => return result,
8799 .none, .coerced_ty => return result,
88038800 .discard => {
88048801 // Emit a compile error for discarding error values.
88058802 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
......@@ -9561,9 +9558,7 @@ const GenZir = struct {
95619558 gz.rl_ty_inst = ty_inst;
95629559 gz.break_result_loc = parent_rl;
95639560 },
9564 .none_or_ref => {
9565 gz.break_result_loc = .ref;
9566 },
9561
95679562 .discard, .none, .ptr, .ref => {
95689563 gz.break_result_loc = parent_rl;
95699564 },
src/Liveness.zig+2
......@@ -300,6 +300,8 @@ fn analyzeInst(
300300 .wrap_errunion_err,
301301 .slice_ptr,
302302 .slice_len,
303 .ptr_slice_len_ptr,
304 .ptr_slice_ptr_ptr,
303305 .struct_field_ptr_index_0,
304306 .struct_field_ptr_index_1,
305307 .struct_field_ptr_index_2,
src/Sema.zig+291-234
......@@ -300,7 +300,7 @@ pub const Block = struct {
300300 .ty = ty,
301301 .payload = try block.sema.addExtra(Air.StructField{
302302 .struct_operand = struct_ptr,
303 .field_index = @intCast(u32, field_index),
303 .field_index = field_index,
304304 }),
305305 } },
306306 });
......@@ -315,6 +315,24 @@ pub const Block = struct {
315315 });
316316 }
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
318336 pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {
319337 return Air.indexToRef(try block.addInstAsIndex(inst));
320338 }
......@@ -1968,44 +1986,38 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
19681986
19691987 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
19701988 const src = inst_data.src();
1971 const array = sema.resolveInst(inst_data.operand);
1972 const array_ty = sema.typeOf(array);
1989 const object = sema.resolveInst(inst_data.operand);
1990 const object_ty = sema.typeOf(object);
19731991
1974 if (array_ty.isSlice()) {
1975 return sema.analyzeSliceLen(block, src, array);
1976 }
1992 const is_pointer_to = object_ty.isSinglePointer();
19771993
1978 if (array_ty.isSinglePointer()) {
1979 const elem_ty = array_ty.elemType();
1980 if (elem_ty.isSlice()) {
1981 const slice_inst = try sema.analyzeLoad(block, src, array, src);
1982 return sema.analyzeSliceLen(block, src, slice_inst);
1983 }
1984 if (!elem_ty.isIndexable()) {
1985 const msg = msg: {
1986 const msg = try sema.errMsg(
1987 block,
1988 src,
1989 "type '{}' does not support indexing",
1990 .{elem_ty},
1991 );
1992 errdefer msg.destroy(sema.gpa);
1993 try sema.errNote(
1994 block,
1995 src,
1996 msg,
1997 "for loop operand must be an array, slice, tuple, or vector",
1998 .{},
1999 );
2000 break :msg msg;
2001 };
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);
1994 const array_ty = if (is_pointer_to)
1995 object_ty.childType()
1996 else
1997 object_ty;
1998
1999 if (!array_ty.isIndexable()) {
2000 const msg = msg: {
2001 const msg = try sema.errMsg(
2002 block,
2003 src,
2004 "type '{}' does not support indexing",
2005 .{array_ty},
2006 );
2007 errdefer msg.destroy(sema.gpa);
2008 try sema.errNote(
2009 block,
2010 src,
2011 msg,
2012 "for loop operand must be an array, slice, tuple, or vector",
2013 .{},
2014 );
2015 break :msg msg;
2016 };
2017 return sema.failWithOwnedErrorMsg(msg);
20062018 }
20072019
2008 return sema.fail(block, src, "TODO implement Sema.zirIndexablePtrLen", .{});
2020 return sema.fieldVal(block, src, object, "len", src);
20092021}
20102022
20112023fn zirAllocExtended(
......@@ -2304,7 +2316,7 @@ fn validateStructInit(
23042316 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
23052317 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
23062318 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);
23082320 if (found_fields[field_index] != 0) {
23092321 const other_field_ptr = found_fields[field_index];
23102322 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
23662378 }
23672379}
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(
23702407 sema: *Sema,
23712408 block: *Block,
23722409 struct_obj: *Module.Struct,
......@@ -5119,16 +5156,10 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
51195156 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
51205157 const src = inst_data.src();
51215158 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
5122 const lhs_src: LazySrcLoc = src; // TODO
51235159 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
51245160 const field_name = sema.code.nullTerminatedString(extra.field_name_start);
51255161 const object = sema.resolveInst(extra.lhs);
5126 if (sema.typeOf(object).isSinglePointer()) {
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 }
5162 return sema.fieldVal(block, src, object, field_name, field_name_src);
51325163}
51335164
51345165fn 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)
88228853 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
88238854 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
88248855 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);
88268857 if (found_fields[field_index] != 0) {
88278858 const other_field_type = found_fields[field_index];
88288859 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
90319062 .Struct => {
90329063 const struct_obj = resolved_ty.castTag(.@"struct").?.data;
90339064 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);
90359066 return sema.addType(field.ty);
90369067 },
90379068 .Union => {
......@@ -9331,7 +9362,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
93319362 const dest_info = dest_ty.intInfo(target);
93329363
93339364 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);
93359366 }
93369367
93379368 if (!src_is_comptime_int) {
......@@ -10688,12 +10719,22 @@ fn fieldVal(
1068810719 const object_src = src; // TODO better source location
1068910720 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()) {
1069210733 .Array => {
1069310734 if (mem.eql(u8, field_name, "len")) {
1069410735 return sema.addConstant(
1069510736 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()),
1069710738 );
1069810739 } else {
1069910740 return sema.fail(
......@@ -10704,75 +10745,60 @@ fn fieldVal(
1070410745 );
1070510746 }
1070610747 },
10707 .Pointer => switch (object_ty.ptrSize()) {
10708 .Slice => {
10709 if (mem.eql(u8, field_name, "ptr")) {
10710 const buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
10711 const result_ty = object_ty.slicePtrFieldType(buf);
10712 if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| {
10713 if (val.isUndef()) return sema.addConstUndef(result_ty);
10714 return sema.addConstant(result_ty, val.slicePtr());
10715 }
10716 try sema.requireRuntimeBlock(block, src);
10717 return block.addTyOp(.slice_ptr, result_ty, object);
10718 } else if (mem.eql(u8, field_name, "len")) {
10719 const result_ty = Type.usize;
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 );
10748 .Pointer => if (inner_ty.isSlice()) {
10749 if (mem.eql(u8, field_name, "ptr")) {
10750 const slice = if (is_pointer_to)
10751 try sema.analyzeLoad(block, src, object, object_src)
10752 else
10753 object;
10754
10755 const buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
10756 const result_ty = inner_ty.slicePtrFieldType(buf);
10757
10758 if (try sema.resolveMaybeUndefVal(block, object_src, slice)) |val| {
10759 if (val.isUndef()) return sema.addConstUndef(result_ty);
10760 return sema.addConstant(result_ty, val.slicePtr());
1073610761 }
10737 },
10738 .One => {
10739 const ptr_child = object_ty.elemType();
10740 switch (ptr_child.zigTypeTag()) {
10741 .Array => {
10742 if (mem.eql(u8, field_name, "len")) {
10743 return sema.addConstant(
10744 Type.initTag(.comptime_int),
10745 try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()),
10746 );
10747 } else {
10748 return sema.fail(
10749 block,
10750 field_name_src,
10751 "no member named '{s}' in '{}'",
10752 .{ field_name, object_ty },
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 => {},
10762 try sema.requireRuntimeBlock(block, src);
10763 return block.addTyOp(.slice_ptr, result_ty, slice);
10764 } else if (mem.eql(u8, field_name, "len")) {
10765 const slice = if (is_pointer_to)
10766 try sema.analyzeLoad(block, src, object, object_src)
10767 else
10768 object;
10769
10770 const result_ty = Type.usize;
10771
10772 if (try sema.resolveMaybeUndefVal(block, object_src, slice)) |val| {
10773 if (val.isUndef()) return sema.addConstUndef(result_ty);
10774 return sema.addConstant(
10775 result_ty,
10776 try Value.Tag.int_u64.create(arena, val.sliceLen()),
10777 );
1076510778 }
10766 },
10767 .Many, .C => {},
10779 try sema.requireRuntimeBlock(block, src);
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 }
1076810789 },
1076910790 .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)).?;
1077110797 var to_type_buffer: Value.ToTypeBuffer = undefined;
1077210798 const child_type = val.toType(&to_type_buffer);
10799
1077310800 switch (child_type.zigTypeTag()) {
1077410801 .ErrorSet => {
10775 // TODO resolve inferred error sets
1077610802 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {
1077710803 const error_set = payload.data;
1077810804 // TODO this is O(N). I'm putting off solving this until we solve inferred
......@@ -10842,8 +10868,20 @@ fn fieldVal(
1084210868 else => return sema.fail(block, src, "type '{}' has no members", .{child_type}),
1084310869 }
1084410870 },
10845 .Struct => return sema.structFieldVal(block, src, object, field_name, field_name_src, object_ty),
10846 .Union => return sema.unionFieldVal(block, src, object, field_name, field_name_src, object_ty),
10871 .Struct => if (is_pointer_to) {
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 },
1084710885 else => {},
1084810886 }
1084910887 return sema.fail(block, src, "type '{}' does not support field access", .{object_ty});
......@@ -10866,14 +10904,25 @@ fn fieldPtr(
1086610904 .Pointer => object_ptr_ty.elemType(),
1086710905 else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty}),
1086810906 };
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()) {
1087010919 .Array => {
1087110920 if (mem.eql(u8, field_name, "len")) {
1087210921 var anon_decl = try block.startAnonDecl();
1087310922 defer anon_decl.deinit();
1087410923 return sema.analyzeDeclRef(try anon_decl.finish(
1087510924 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()),
1087710926 ));
1087810927 } else {
1087910928 return sema.fail(
......@@ -10884,77 +10933,74 @@ fn fieldPtr(
1088410933 );
1088510934 }
1088610935 },
10887 .Pointer => switch (object_ty.ptrSize()) {
10888 .Slice => {
10889 // Here for the ptr and len fields what we need to do is the situation
10890 // when a temporary has its address taken, e.g. `&a[c..d].len`.
10891 // This value may be known at compile-time or runtime. In the former
10892 // case, it should create an anonymous Decl and return a decl_ref to it.
10893 // In the latter case, it should add an `alloc` instruction, store
10894 // the runtime value to it, and then return the `alloc`.
10895 // In both cases the pointer should be const.
10896 if (mem.eql(u8, field_name, "ptr")) {
10897 return sema.fail(
10898 block,
10899 field_name_src,
10900 "TODO: implement reference to 'ptr' field of slice '{}'",
10901 .{object_ty},
10902 );
10903 } else if (mem.eql(u8, field_name, "len")) {
10904 return sema.fail(
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 );
10936 .Pointer => if (inner_ty.isSlice()) {
10937 const inner_ptr = if (is_pointer_to)
10938 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
10939 else
10940 object_ptr;
10941
10942 if (mem.eql(u8, field_name, "ptr")) {
10943 const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer);
10944 const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);
10945
10946 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
10947 var anon_decl = try block.startAnonDecl();
10948 defer anon_decl.deinit();
10949
10950 return sema.analyzeDeclRef(try anon_decl.finish(
10951 try slice_ptr_ty.copy(anon_decl.arena()),
10952 try val.slicePtr().copy(anon_decl.arena()),
10953 ));
1091710954 }
10918 },
10919 .One => {
10920 const ptr_child = object_ty.elemType();
10921 switch (ptr_child.zigTypeTag()) {
10922 .Array => {
10923 if (mem.eql(u8, field_name, "len")) {
10924 var anon_decl = try block.startAnonDecl();
10925 defer anon_decl.deinit();
10926 return sema.analyzeDeclRef(try anon_decl.finish(
10927 Type.initTag(.comptime_int),
10928 try Value.Tag.int_u64.create(anon_decl.arena(), ptr_child.arrayLen()),
10929 ));
10930 } else {
10931 return sema.fail(
10932 block,
10933 field_name_src,
10934 "no member named '{s}' in '{}'",
10935 .{ field_name, object_ty },
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 => {},
10955 try sema.requireRuntimeBlock(block, src);
10956
10957 const result_ty = try Type.ptr(sema.arena, .{
10958 .pointee_type = slice_ptr_ty,
10959 .mutable = object_ptr_ty.ptrIsMutable(),
10960 .@"addrspace" = object_ptr_ty.ptrAddressSpace(),
10961 });
10962
10963 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
10964 } else if (mem.eql(u8, field_name, "len")) {
10965 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
10966 var anon_decl = try block.startAnonDecl();
10967 defer anon_decl.deinit();
10968
10969 return sema.analyzeDeclRef(try anon_decl.finish(
10970 Type.usize,
10971 try Value.Tag.int_u64.create(anon_decl.arena(), val.sliceLen()),
10972 ));
1094810973 }
10949 },
10950 .Many, .C => {},
10974 try sema.requireRuntimeBlock(block, src);
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 }
1095110991 },
1095210992 .Type => {
1095310993 _ = try sema.resolveConstValue(block, object_ptr_src, object_ptr);
1095410994 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).?;
1095611001 var to_type_buffer: Value.ToTypeBuffer = undefined;
1095711002 const child_type = val.toType(&to_type_buffer);
11003
1095811004 switch (child_type.zigTypeTag()) {
1095911005 .ErrorSet => {
1096011006 // TODO resolve inferred error sets
......@@ -10980,22 +11026,24 @@ fn fieldPtr(
1098011026 try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),
1098111027 ));
1098211028 },
10983 .Struct, .Opaque, .Union => {
11029 .Union => {
1098411030 if (child_type.getNamespace()) |namespace| {
1098511031 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
1098611032 return inst;
1098711033 }
1098811034 }
10989 // TODO add note: declared here
10990 const kw_name = switch (child_type.zigTypeTag()) {
10991 .Struct => "struct",
10992 .Opaque => "opaque",
10993 .Union => "union",
10994 else => unreachable,
10995 };
10996 return sema.fail(block, src, "{s} '{}' has no member named '{s}'", .{
10997 kw_name, child_type, field_name,
10998 });
11035 if (child_type.unionTagType()) |enum_ty| {
11036 if (enum_ty.enumFieldIndex(field_name)) |field_index| {
11037 const field_index_u32 = @intCast(u32, field_index);
11038 var anon_decl = try block.startAnonDecl();
11039 defer anon_decl.deinit();
11040 return sema.analyzeDeclRef(try anon_decl.finish(
11041 try enum_ty.copy(anon_decl.arena()),
11042 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
11043 ));
11044 }
11045 }
11046 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
1099911047 },
1100011048 .Enum => {
1100111049 if (child_type.getNamespace()) |namespace| {
......@@ -11004,23 +11052,7 @@ fn fieldPtr(
1100411052 }
1100511053 }
1100611054 const field_index = child_type.enumFieldIndex(field_name) orelse {
11007 const msg = msg: {
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);
11055 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
1102411056 };
1102511057 const field_index_u32 = @intCast(u32, field_index);
1102611058 var anon_decl = try block.startAnonDecl();
......@@ -11030,14 +11062,34 @@ fn fieldPtr(
1103011062 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
1103111063 ));
1103211064 },
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 },
1103311073 else => return sema.fail(block, src, "type '{}' has no members", .{child_type}),
1103411074 }
1103511075 },
11036 .Struct => return sema.structFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty),
11037 .Union => return sema.unionFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty),
11076 .Struct => {
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 },
1103811090 else => {},
1103911091 }
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 });
1104111093}
1104211094
1104311095fn fieldCallBind(
......@@ -11209,7 +11261,7 @@ fn structFieldPtr(
1120911261 const struct_obj = struct_ty.castTag(.@"struct").?.data;
1121011262
1121111263 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);
1121311265 const field_index = @intCast(u32, field_index_big);
1121411266 const field = struct_obj.fields.values()[field_index];
1121511267 const ptr_field_ty = try Type.ptr(arena, .{
......@@ -11246,8 +11298,9 @@ fn structFieldVal(
1124611298 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);
1124711299 const struct_obj = struct_ty.castTag(.@"struct").?.data;
1124811300
11249 const field_index = struct_obj.fields.getIndex(field_name) orelse
11250 return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);
11301 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
11302 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
11303 const field_index = @intCast(u32, field_index_usize);
1125111304 const field = struct_obj.fields.values()[field_index];
1125211305
1125311306 if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| {
......@@ -11258,16 +11311,7 @@ fn structFieldVal(
1125811311 }
1125911312
1126011313 try sema.requireRuntimeBlock(block, src);
11261 return block.addInst(.{
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 });
11314 return block.addStructFieldVal(struct_byval, field_index, field.ty);
1127111315}
1127211316
1127311317fn unionFieldPtr(
......@@ -11326,8 +11370,9 @@ fn unionFieldVal(
1132611370 const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);
1132711371 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
1132811372
11329 const field_index = union_obj.fields.getIndex(field_name) orelse
11373 const field_index_big = union_obj.fields.getIndex(field_name) orelse
1133011374 return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name);
11375 const field_index = @intCast(u32, field_index_big);
1133111376
1133211377 const field = union_obj.fields.values()[field_index];
1133311378
......@@ -11340,7 +11385,7 @@ fn unionFieldVal(
1134011385 }
1134111386
1134211387 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);
1134411389}
1134511390
1134611391fn elemPtr(
......@@ -13141,6 +13186,10 @@ pub fn resolveTypeLayout(
1314113186 }
1314213187 union_obj.status = .have_layout;
1314313188 },
13189 .Array => {
13190 const elem_ty = ty.childType();
13191 return sema.resolveTypeLayout(block, src, elem_ty);
13192 },
1314413193 else => {},
1314513194 }
1314613195}
......@@ -13693,10 +13742,9 @@ fn typeHasOnePossibleValue(
1369313742 sema: *Sema,
1369413743 block: *Block,
1369513744 src: LazySrcLoc,
13696 starting_type: Type,
13745 ty: Type,
1369713746) CompileError!?Value {
13698 var ty = starting_type;
13699 while (true) switch (ty.tag()) {
13747 switch (ty.tag()) {
1370013748 .f16,
1370113749 .f32,
1370213750 .f64,
......@@ -13790,7 +13838,7 @@ fn typeHasOnePossibleValue(
1379013838 const enum_obj = resolved_ty.castTag(.enum_numbered).?.data;
1379113839 if (enum_obj.fields.count() == 1) {
1379213840 if (enum_obj.values.count() == 0) {
13793 return Value.initTag(.zero); // auto-numbered
13841 return Value.zero; // auto-numbered
1379413842 } else {
1379513843 return enum_obj.values.keys()[0];
1379613844 }
......@@ -13803,7 +13851,7 @@ fn typeHasOnePossibleValue(
1380313851 const enum_obj = resolved_ty.castTag(.enum_full).?.data;
1380413852 if (enum_obj.fields.count() == 1) {
1380513853 if (enum_obj.values.count() == 0) {
13806 return Value.initTag(.zero); // auto-numbered
13854 return Value.zero; // auto-numbered
1380713855 } else {
1380813856 return enum_obj.values.keys()[0];
1380913857 }
......@@ -13815,12 +13863,19 @@ fn typeHasOnePossibleValue(
1381513863 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
1381613864 const enum_simple = resolved_ty.castTag(.enum_simple).?.data;
1381713865 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;
1381913875 } else {
1382013876 return null;
1382113877 }
1382213878 },
13823 .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty,
1382413879 .@"union" => {
1382513880 return null; // TODO
1382613881 },
......@@ -13836,7 +13891,7 @@ fn typeHasOnePossibleValue(
1383613891
1383713892 .int_unsigned, .int_signed => {
1383813893 if (ty.cast(Type.Payload.Bits).?.data == 0) {
13839 return Value.initTag(.zero);
13894 return Value.zero;
1384013895 } else {
1384113896 return null;
1384213897 }
......@@ -13844,14 +13899,16 @@ fn typeHasOnePossibleValue(
1384413899 .vector, .array, .array_u8 => {
1384513900 if (ty.arrayLen() == 0)
1384613901 return Value.initTag(.empty_array);
13847 ty = ty.elemType();
13848 continue;
13902 if ((try sema.typeHasOnePossibleValue(block, src, ty.elemType())) != null) {
13903 return Value.initTag(.the_only_possible_value);
13904 }
13905 return null;
1384913906 },
1385013907
1385113908 .inferred_alloc_const => unreachable,
1385213909 .inferred_alloc_mut => unreachable,
1385313910 .generic_poison => return error.GenericPoison,
13854 };
13911 }
1385513912}
1385613913
1385713914fn 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 {
494494 .slice_ptr => try self.airSlicePtr(inst),
495495 .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
497500 .array_elem_val => try self.airArrayElemVal(inst),
498501 .slice_elem_val => try self.airSliceElemVal(inst),
499502 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),
......@@ -1057,6 +1060,18 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
10571060 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
10581061}
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
10601075fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
10611076 const is_volatile = false; // TODO
10621077 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 {
842842 .slice_ptr => try self.airSlicePtr(inst),
843843 .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
845848 .array_elem_val => try self.airArrayElemVal(inst),
846849 .slice_elem_val => try self.airSliceElemVal(inst),
847850 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),
......@@ -1498,6 +1501,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
14981501 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
14991502 }
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
15011520 fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
15021521 const is_volatile = false; // TODO
15031522 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
10751075 .slice_ptr => try airSliceField(f, inst, ".ptr;\n"),
10761076 .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
10781081 .ptr_elem_val => try airPtrElemVal(f, inst, "["),
10791082 .ptr_ptr_elem_val => try airPtrElemVal(f, inst, "[0]["),
10801083 .ptr_elem_ptr => try airPtrElemPtr(f, inst),
......@@ -1114,6 +1117,21 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue
11141117 return local;
11151118}
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
11171135fn airPtrElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue {
11181136 const is_volatile = false; // TODO
11191137 if (!is_volatile and f.liveness.isUnused(inst))
src/codegen/llvm.zig+44-10
......@@ -1261,6 +1261,10 @@ pub const DeclGen = struct {
12611261 }
12621262 const field_ty = tv.ty.unionFieldType(tag_and_val.tag);
12631263 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 }
12641268 const field = try genTypedValue(self, .{ .ty = field_ty, .val = tag_and_val.val });
12651269 const field_size = field_ty.abiSize(target);
12661270 if (field_size == layout.payload_size) {
......@@ -1709,6 +1713,10 @@ pub const FuncGen = struct {
17091713 .assembly => try self.airAssembly(inst),
17101714 .slice_ptr => try self.airSliceField(inst, 0),
17111715 .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
17121720 .array_to_slice => try self.airArrayToSlice(inst),
17131721 .float_to_int => try self.airFloatToInt(inst),
17141722 .int_to_float => try self.airIntToFloat(inst),
......@@ -2091,6 +2099,15 @@ pub const FuncGen = struct {
20912099 return self.builder.buildExtractValue(operand, index, "");
20922100 }
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
20942111 fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
20952112 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
20962113 const slice_ty = self.air.typeOf(bin_op.lhs);
......@@ -2223,17 +2240,34 @@ pub const FuncGen = struct {
22232240 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
22242241 const struct_ty = self.air.typeOf(struct_field.struct_operand);
22252242 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);
2226 const field_index = llvmFieldIndex(struct_ty, struct_field.field_index);
2227 if (isByRef(struct_ty)) {
2228 const field_ptr = self.builder.buildStructGEP(struct_llvm_val, field_index, "");
2229 const field_ty = struct_ty.structFieldType(struct_field.field_index);
2230 if (isByRef(field_ty)) {
2231 return field_ptr;
2232 } else {
2233 return self.builder.buildLoad(field_ptr, "");
2234 }
2243 const field_index = struct_field.field_index;
2244 const field_ty = struct_ty.structFieldType(field_index);
2245 if (!field_ty.hasCodeGenBits()) {
2246 return null;
2247 }
2248
2249 assert(isByRef(struct_ty));
2250
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;
22352269 } else {
2236 return self.builder.buildExtractValue(struct_llvm_val, field_index, "");
2270 return self.builder.buildLoad(field_ptr, "");
22372271 }
22382272 }
22392273
src/codegen/wasm.zig+10
......@@ -866,6 +866,7 @@ pub const Context = struct {
866866 .struct_field_ptr_index_1 => self.airStructFieldPtrIndex(inst, 1),
867867 .struct_field_ptr_index_2 => self.airStructFieldPtrIndex(inst, 2),
868868 .struct_field_ptr_index_3 => self.airStructFieldPtrIndex(inst, 3),
869 .struct_field_val => self.airStructFieldVal(inst),
869870 .switch_br => self.airSwitchBr(inst),
870871 .unreach => self.airUnreachable(inst),
871872 .wrap_optional => self.airWrapOptional(inst),
......@@ -1456,6 +1457,15 @@ pub const Context = struct {
14561457 return WValue{ .local = struct_ptr.multi_value.index + index };
14571458 }
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
14591469 fn airSwitchBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
14601470 // result type is always 'noreturn'
14611471 const blocktype = wasm.block_empty;
src/print_air.zig+2
......@@ -183,6 +183,8 @@ const Writer = struct {
183183 .wrap_errunion_err,
184184 .slice_ptr,
185185 .slice_len,
186 .ptr_slice_len_ptr,
187 .ptr_slice_ptr_ptr,
186188 .struct_field_ptr_index_0,
187189 .struct_field_ptr_index_1,
188190 .struct_field_ptr_index_2,
src/type.zig+24-9
......@@ -2676,7 +2676,7 @@ pub const Type = extern union {
26762676
26772677 .pointer => return self.castTag(.pointer).?.data.sentinel,
26782678 .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
26812681 else => unreachable,
26822682 };
......@@ -3096,6 +3096,14 @@ pub const Type = extern union {
30963096 }
30973097 return Value.initTag(.empty_struct_value);
30983098 },
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 },
30993107 .enum_full => {
31003108 const enum_full = ty.castTag(.enum_full).?.data;
31013109 if (enum_full.fields.count() == 1) {
......@@ -3107,13 +3115,19 @@ pub const Type = extern union {
31073115 .enum_simple => {
31083116 const enum_simple = ty.castTag(.enum_simple).?.data;
31093117 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;
31113127 } else {
31123128 return null;
31133129 }
31143130 },
3115 .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty,
3116 .enum_numbered => ty = ty.castTag(.enum_numbered).?.data.tag_ty,
31173131 .@"union" => {
31183132 return null; // TODO
31193133 },
......@@ -3129,7 +3143,7 @@ pub const Type = extern union {
31293143
31303144 .int_unsigned, .int_signed => {
31313145 if (ty.cast(Payload.Bits).?.data == 0) {
3132 return Value.initTag(.zero);
3146 return Value.zero;
31333147 } else {
31343148 return null;
31353149 }
......@@ -3137,8 +3151,9 @@ pub const Type = extern union {
31373151 .vector, .array, .array_u8 => {
31383152 if (ty.arrayLen() == 0)
31393153 return Value.initTag(.empty_array);
3140 ty = ty.elemType();
3141 continue;
3154 if (ty.elemType().onePossibleValue() != null)
3155 return Value.initTag(.the_only_possible_value);
3156 return null;
31423157 },
31433158
31443159 .inferred_alloc_const => unreachable,
......@@ -3179,7 +3194,7 @@ pub const Type = extern union {
31793194 const info = self.intInfo(target);
31803195
31813196 if (info.signedness == .unsigned) {
3182 return Value.initTag(.zero);
3197 return Value.zero;
31833198 }
31843199
31853200 if (info.bits <= 6) {
......@@ -4013,7 +4028,7 @@ pub const Type = extern union {
40134028 ) Allocator.Error!Type {
40144029 if (elem_type.eql(Type.u8)) {
40154030 if (sent) |some| {
4016 if (some.eql(Value.initTag(.zero), elem_type)) {
4031 if (some.eql(Value.zero, elem_type)) {
40174032 return Tag.array_u8_sentinel_0.create(arena, len);
40184033 }
40194034 } else {
src/value.zig+74-37
......@@ -86,6 +86,8 @@ pub const Value = extern union {
8686 one,
8787 void_value,
8888 unreachable_value,
89 /// The only possible value for a particular type, which is stored externally.
90 the_only_possible_value,
8991 null_value,
9092 bool_true,
9193 bool_false,
......@@ -226,6 +228,7 @@ pub const Value = extern union {
226228 .one,
227229 .void_value,
228230 .unreachable_value,
231 .the_only_possible_value,
229232 .empty_struct_value,
230233 .empty_array,
231234 .null_value,
......@@ -415,6 +418,7 @@ pub const Value = extern union {
415418 .one,
416419 .void_value,
417420 .unreachable_value,
421 .the_only_possible_value,
418422 .empty_array,
419423 .null_value,
420424 .bool_true,
......@@ -664,6 +668,7 @@ pub const Value = extern union {
664668 .one => return out_stream.writeAll("1"),
665669 .void_value => return out_stream.writeAll("{}"),
666670 .unreachable_value => return out_stream.writeAll("unreachable"),
671 .the_only_possible_value => return out_stream.writeAll("(the only possible value)"),
667672 .bool_true => return out_stream.writeAll("true"),
668673 .bool_false => return out_stream.writeAll("false"),
669674 .ty => return val.castTag(.ty).?.data.format("", options, out_stream),
......@@ -755,6 +760,7 @@ pub const Value = extern union {
755760 const decl_val = try decl.value();
756761 return decl_val.toAllocatedBytes(decl.ty, allocator);
757762 },
763 .the_only_possible_value => return &[_]u8{},
758764 else => unreachable,
759765 }
760766 }
......@@ -847,53 +853,63 @@ pub const Value = extern union {
847853 // TODO should `@intToEnum` do this `@intCast` for you?
848854 return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));
849855 },
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 },
850861 else => unreachable,
851862 }
852863 }
853864
854865 pub fn enumToInt(val: Value, ty: Type, buffer: *Payload.U64) Value {
855 if (val.castTag(.enum_field_index)) |enum_field_payload| {
856 const field_index = enum_field_payload.data;
857 switch (ty.tag()) {
858 .enum_full, .enum_nonexhaustive => {
859 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
860 if (enum_full.values.count() != 0) {
861 return enum_full.values.keys()[field_index];
862 } else {
863 // Field index and integer values are the same.
864 buffer.* = .{
865 .base = .{ .tag = .int_u64 },
866 .data = field_index,
867 };
868 return Value.initPayload(&buffer.base);
869 }
870 },
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 => {
866 const field_index = switch (val.tag()) {
867 .enum_field_index => val.castTag(.enum_field_index).?.data,
868 .the_only_possible_value => blk: {
869 assert(ty.enumFieldCount() == 1);
870 break :blk 0;
871 },
872 // Assume it is already an integer and return it directly.
873 else => return val,
874 };
875
876 switch (ty.tag()) {
877 .enum_full, .enum_nonexhaustive => {
878 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
879 if (enum_full.values.count() != 0) {
880 return enum_full.values.keys()[field_index];
881 } else {
885882 // Field index and integer values are the same.
886883 buffer.* = .{
887884 .base = .{ .tag = .int_u64 },
888885 .data = field_index,
889886 };
890887 return Value.initPayload(&buffer.base);
891 },
892 else => unreachable,
893 }
888 }
889 },
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,
894912 }
895 // Assume it is already an integer and return it directly.
896 return val;
897913 }
898914
899915 /// Asserts the value is an integer.
......@@ -901,6 +917,7 @@ pub const Value = extern union {
901917 switch (self.tag()) {
902918 .zero,
903919 .bool_false,
920 .the_only_possible_value, // i0, u0
904921 => return BigIntMutable.init(&space.limbs, 0).toConst(),
905922
906923 .one,
......@@ -922,6 +939,7 @@ pub const Value = extern union {
922939 switch (self.tag()) {
923940 .zero,
924941 .bool_false,
942 .the_only_possible_value, // i0, u0
925943 => return 0,
926944
927945 .one,
......@@ -943,6 +961,7 @@ pub const Value = extern union {
943961 switch (self.tag()) {
944962 .zero,
945963 .bool_false,
964 .the_only_possible_value, // i0, u0
946965 => return 0,
947966
948967 .one,
......@@ -1124,6 +1143,11 @@ pub const Value = extern union {
11241143 @panic("TODO implement int_big_negative Value clz");
11251144 },
11261145
1146 .the_only_possible_value => {
1147 assert(ty_bits == 0);
1148 return ty_bits;
1149 },
1150
11271151 else => unreachable,
11281152 }
11291153 }
......@@ -1134,6 +1158,7 @@ pub const Value = extern union {
11341158 switch (self.tag()) {
11351159 .zero,
11361160 .bool_false,
1161 .the_only_possible_value,
11371162 => return 0,
11381163
11391164 .one,
......@@ -1213,6 +1238,11 @@ pub const Value = extern union {
12131238 else => unreachable,
12141239 },
12151240
1241 .the_only_possible_value => {
1242 assert(ty.intInfo(target).bits == 0);
1243 return true;
1244 },
1245
12161246 else => unreachable,
12171247 }
12181248 }
......@@ -1251,7 +1281,7 @@ pub const Value = extern union {
12511281 /// Asserts the value is numeric
12521282 pub fn isZero(self: Value) bool {
12531283 return switch (self.tag()) {
1254 .zero => true,
1284 .zero, .the_only_possible_value => true,
12551285 .one => false,
12561286
12571287 .int_u64 => self.castTag(.int_u64).?.data == 0,
......@@ -1272,6 +1302,7 @@ pub const Value = extern union {
12721302 return switch (lhs.tag()) {
12731303 .zero,
12741304 .bool_false,
1305 .the_only_possible_value,
12751306 => .eq,
12761307
12771308 .one,
......@@ -1354,7 +1385,7 @@ pub const Value = extern union {
13541385 assert(b_tag != .undef);
13551386 if (a_tag == b_tag) {
13561387 switch (a_tag) {
1357 .void_value, .null_value => return true,
1388 .void_value, .null_value, .the_only_possible_value => return true,
13581389 .enum_literal => {
13591390 const a_name = a.castTag(.enum_literal).?.data;
13601391 const b_name = b.castTag(.enum_literal).?.data;
......@@ -1706,6 +1737,9 @@ pub const Value = extern union {
17061737 .decl_ref => return val.castTag(.decl_ref).?.data.val.elemValueAdvanced(index, arena, buffer),
17071738 .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
17091743 else => unreachable,
17101744 }
17111745 }
......@@ -1722,6 +1756,8 @@ pub const Value = extern union {
17221756 // TODO assert the tag is correct
17231757 return payload.val;
17241758 },
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
17261762 else => unreachable,
17271763 }
......@@ -1820,6 +1856,7 @@ pub const Value = extern union {
18201856 pub fn intToFloat(val: Value, allocator: *Allocator, dest_ty: Type, target: Target) !Value {
18211857 switch (val.tag()) {
18221858 .undef, .zero, .one => return val,
1859 .the_only_possible_value => return Value.initTag(.zero), // for i0, u0
18231860 .int_u64 => {
18241861 return intToFloatInner(val.castTag(.int_u64).?.data, allocator, dest_ty, target);
18251862 },