| ... | @@ -5119,16 +5119,10 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -5119,16 +5119,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; | 5119 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 5120 | const src = inst_data.src(); | 5120 | const src = inst_data.src(); |
| 5121 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; | 5121 | 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; | 5122 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; |
| 5124 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); | 5123 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); |
| 5125 | const object = sema.resolveInst(extra.lhs); | 5124 | const object = sema.resolveInst(extra.lhs); |
| 5126 | if (sema.typeOf(object).isSinglePointer()) { | 5125 | 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 | } | 5126 | } |
| 5133 | | 5127 | |
| 5134 | fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 5128 | fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -10688,12 +10682,22 @@ fn fieldVal( | ... | @@ -10688,12 +10682,22 @@ fn fieldVal( |
| 10688 | const object_src = src; // TODO better source location | 10682 | const object_src = src; // TODO better source location |
| 10689 | const object_ty = sema.typeOf(object); | 10683 | const object_ty = sema.typeOf(object); |
| 10690 | | 10684 | |
| 10691 | switch (object_ty.zigTypeTag()) { | 10685 | // Zig allows dereferencing a single pointer during field lookup. Note that |
| | 10686 | // we don't actually need to generate the dereference some field lookups, like the |
| | 10687 | // length of arrays and other comptime operations. |
| | 10688 | const is_pointer_to = object_ty.isSinglePointer(); |
| | 10689 | |
| | 10690 | const inner_ty = if (is_pointer_to) |
| | 10691 | object_ty.childType() |
| | 10692 | else |
| | 10693 | object_ty; |
| | 10694 | |
| | 10695 | switch (inner_ty.zigTypeTag()) { |
| 10692 | .Array => { | 10696 | .Array => { |
| 10693 | if (mem.eql(u8, field_name, "len")) { | 10697 | if (mem.eql(u8, field_name, "len")) { |
| 10694 | return sema.addConstant( | 10698 | return sema.addConstant( |
| 10695 | Type.initTag(.comptime_int), | 10699 | Type.initTag(.comptime_int), |
| 10696 | try Value.Tag.int_u64.create(arena, object_ty.arrayLen()), | 10700 | try Value.Tag.int_u64.create(arena, inner_ty.arrayLen()), |
| 10697 | ); | 10701 | ); |
| 10698 | } else { | 10702 | } else { |
| 10699 | return sema.fail( | 10703 | return sema.fail( |
| ... | @@ -10704,75 +10708,60 @@ fn fieldVal( | ... | @@ -10704,75 +10708,60 @@ fn fieldVal( |
| 10704 | ); | 10708 | ); |
| 10705 | } | 10709 | } |
| 10706 | }, | 10710 | }, |
| 10707 | .Pointer => switch (object_ty.ptrSize()) { | 10711 | .Pointer => if (inner_ty.isSlice()) { |
| 10708 | .Slice => { | 10712 | if (mem.eql(u8, field_name, "ptr")) { |
| 10709 | if (mem.eql(u8, field_name, "ptr")) { | 10713 | const slice = if (is_pointer_to) |
| 10710 | const buf = try arena.create(Type.SlicePtrFieldTypeBuffer); | 10714 | try sema.analyzeLoad(block, src, object, object_src) |
| 10711 | const result_ty = object_ty.slicePtrFieldType(buf); | 10715 | else |
| 10712 | if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| { | 10716 | object; |
| 10713 | if (val.isUndef()) return sema.addConstUndef(result_ty); | 10717 | |
| 10714 | return sema.addConstant(result_ty, val.slicePtr()); | 10718 | const buf = try arena.create(Type.SlicePtrFieldTypeBuffer); |
| 10715 | } | 10719 | const result_ty = inner_ty.slicePtrFieldType(buf); |
| 10716 | try sema.requireRuntimeBlock(block, src); | 10720 | |
| 10717 | return block.addTyOp(.slice_ptr, result_ty, object); | 10721 | if (try sema.resolveMaybeUndefVal(block, object_src, slice)) |val| { |
| 10718 | } else if (mem.eql(u8, field_name, "len")) { | 10722 | if (val.isUndef()) return sema.addConstUndef(result_ty); |
| 10719 | const result_ty = Type.usize; | 10723 | 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 | } | 10724 | } |
| 10737 | }, | 10725 | try sema.requireRuntimeBlock(block, src); |
| 10738 | .One => { | 10726 | return block.addTyOp(.slice_ptr, result_ty, slice); |
| 10739 | const ptr_child = object_ty.elemType(); | 10727 | } else if (mem.eql(u8, field_name, "len")) { |
| 10740 | switch (ptr_child.zigTypeTag()) { | 10728 | const slice = if (is_pointer_to) |
| 10741 | .Array => { | 10729 | try sema.analyzeLoad(block, src, object, object_src) |
| 10742 | if (mem.eql(u8, field_name, "len")) { | 10730 | else |
| 10743 | return sema.addConstant( | 10731 | object; |
| 10744 | Type.initTag(.comptime_int), | 10732 | |
| 10745 | try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()), | 10733 | const result_ty = Type.usize; |
| 10746 | ); | 10734 | |
| 10747 | } else { | 10735 | if (try sema.resolveMaybeUndefVal(block, object_src, slice)) |val| { |
| 10748 | return sema.fail( | 10736 | if (val.isUndef()) return sema.addConstUndef(result_ty); |
| 10749 | block, | 10737 | return sema.addConstant( |
| 10750 | field_name_src, | 10738 | result_ty, |
| 10751 | "no member named '{s}' in '{}'", | 10739 | try Value.Tag.int_u64.create(arena, val.sliceLen()), |
| 10752 | .{ field_name, object_ty }, | 10740 | ); |
| 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 | } | 10741 | } |
| 10766 | }, | 10742 | try sema.requireRuntimeBlock(block, src); |
| 10767 | .Many, .C => {}, | 10743 | return block.addTyOp(.slice_len, result_ty, slice); |
| | 10744 | } else { |
| | 10745 | return sema.fail( |
| | 10746 | block, |
| | 10747 | field_name_src, |
| | 10748 | "no member named '{s}' in '{}'", |
| | 10749 | .{ field_name, object_ty }, |
| | 10750 | ); |
| | 10751 | } |
| 10768 | }, | 10752 | }, |
| 10769 | .Type => { | 10753 | .Type => { |
| 10770 | const val = (try sema.resolveDefinedValue(block, object_src, object)).?; | 10754 | const dereffed_type = if (is_pointer_to) |
| | 10755 | try sema.analyzeLoad(block, src, object, object_src) |
| | 10756 | else |
| | 10757 | object; |
| | 10758 | |
| | 10759 | const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?; |
| 10771 | var to_type_buffer: Value.ToTypeBuffer = undefined; | 10760 | var to_type_buffer: Value.ToTypeBuffer = undefined; |
| 10772 | const child_type = val.toType(&to_type_buffer); | 10761 | const child_type = val.toType(&to_type_buffer); |
| | 10762 | |
| 10773 | switch (child_type.zigTypeTag()) { | 10763 | switch (child_type.zigTypeTag()) { |
| 10774 | .ErrorSet => { | 10764 | .ErrorSet => { |
| 10775 | // TODO resolve inferred error sets | | |
| 10776 | const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: { | 10765 | const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: { |
| 10777 | const error_set = payload.data; | 10766 | const error_set = payload.data; |
| 10778 | // TODO this is O(N). I'm putting off solving this until we solve inferred | 10767 | // TODO this is O(N). I'm putting off solving this until we solve inferred |
| ... | @@ -10842,8 +10831,20 @@ fn fieldVal( | ... | @@ -10842,8 +10831,20 @@ fn fieldVal( |
| 10842 | else => return sema.fail(block, src, "type '{}' has no members", .{child_type}), | 10831 | else => return sema.fail(block, src, "type '{}' has no members", .{child_type}), |
| 10843 | } | 10832 | } |
| 10844 | }, | 10833 | }, |
| 10845 | .Struct => return sema.structFieldVal(block, src, object, field_name, field_name_src, object_ty), | 10834 | .Struct => if (is_pointer_to) { |
| 10846 | .Union => return sema.unionFieldVal(block, src, object, field_name, field_name_src, object_ty), | 10835 | // Avoid loading the entire struct by fetching a pointer and loading that |
| | 10836 | const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty); |
| | 10837 | return sema.analyzeLoad(block, src, field_ptr, object_src); |
| | 10838 | } else { |
| | 10839 | return sema.structFieldVal(block, src, object, field_name, field_name_src, inner_ty); |
| | 10840 | }, |
| | 10841 | .Union => if (is_pointer_to) { |
| | 10842 | // Avoid loading the entire union by fetching a pointer and loading that |
| | 10843 | const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty); |
| | 10844 | return sema.analyzeLoad(block, src, field_ptr, object_src); |
| | 10845 | } else { |
| | 10846 | return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty); |
| | 10847 | }, |
| 10847 | else => {}, | 10848 | else => {}, |
| 10848 | } | 10849 | } |
| 10849 | return sema.fail(block, src, "type '{}' does not support field access", .{object_ty}); | 10850 | return sema.fail(block, src, "type '{}' does not support field access", .{object_ty}); |
| ... | @@ -10866,14 +10867,25 @@ fn fieldPtr( | ... | @@ -10866,14 +10867,25 @@ fn fieldPtr( |
| 10866 | .Pointer => object_ptr_ty.elemType(), | 10867 | .Pointer => object_ptr_ty.elemType(), |
| 10867 | else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty}), | 10868 | else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty}), |
| 10868 | }; | 10869 | }; |
| 10869 | switch (object_ty.zigTypeTag()) { | 10870 | |
| | 10871 | // Zig allows dereferencing a single pointer during field lookup. Note that |
| | 10872 | // we don't actually need to generate the dereference some field lookups, like the |
| | 10873 | // length of arrays and other comptime operations. |
| | 10874 | const is_pointer_to = object_ty.isSinglePointer(); |
| | 10875 | |
| | 10876 | const inner_ty = if (is_pointer_to) |
| | 10877 | object_ty.childType() |
| | 10878 | else |
| | 10879 | object_ty; |
| | 10880 | |
| | 10881 | switch (inner_ty.zigTypeTag()) { |
| 10870 | .Array => { | 10882 | .Array => { |
| 10871 | if (mem.eql(u8, field_name, "len")) { | 10883 | if (mem.eql(u8, field_name, "len")) { |
| 10872 | var anon_decl = try block.startAnonDecl(); | 10884 | var anon_decl = try block.startAnonDecl(); |
| 10873 | defer anon_decl.deinit(); | 10885 | defer anon_decl.deinit(); |
| 10874 | return sema.analyzeDeclRef(try anon_decl.finish( | 10886 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 10875 | Type.initTag(.comptime_int), | 10887 | Type.initTag(.comptime_int), |
| 10876 | try Value.Tag.int_u64.create(anon_decl.arena(), object_ty.arrayLen()), | 10888 | try Value.Tag.int_u64.create(anon_decl.arena(), inner_ty.arrayLen()), |
| 10877 | )); | 10889 | )); |
| 10878 | } else { | 10890 | } else { |
| 10879 | return sema.fail( | 10891 | return sema.fail( |
| ... | @@ -10884,77 +10896,49 @@ fn fieldPtr( | ... | @@ -10884,77 +10896,49 @@ fn fieldPtr( |
| 10884 | ); | 10896 | ); |
| 10885 | } | 10897 | } |
| 10886 | }, | 10898 | }, |
| 10887 | .Pointer => switch (object_ty.ptrSize()) { | 10899 | .Pointer => if (inner_ty.isSlice()) { |
| 10888 | .Slice => { | 10900 | // Here for the ptr and len fields what we need to do is the situation |
| 10889 | // Here for the ptr and len fields what we need to do is the situation | 10901 | // when a temporary has its address taken, e.g. `&a[c..d].len`. |
| 10890 | // when a temporary has its address taken, e.g. `&a[c..d].len`. | 10902 | // This value may be known at compile-time or runtime. In the former |
| 10891 | // This value may be known at compile-time or runtime. In the former | 10903 | // case, it should create an anonymous Decl and return a decl_ref to it. |
| 10892 | // case, it should create an anonymous Decl and return a decl_ref to it. | 10904 | // In the latter case, it should add an `alloc` instruction, store |
| 10893 | // In the latter case, it should add an `alloc` instruction, store | 10905 | // the runtime value to it, and then return the `alloc`. |
| 10894 | // the runtime value to it, and then return the `alloc`. | 10906 | // In both cases the pointer should be const. |
| 10895 | // In both cases the pointer should be const. | 10907 | if (mem.eql(u8, field_name, "ptr")) { |
| 10896 | if (mem.eql(u8, field_name, "ptr")) { | 10908 | return sema.fail( |
| 10897 | return sema.fail( | 10909 | block, |
| 10898 | block, | 10910 | field_name_src, |
| 10899 | field_name_src, | 10911 | "TODO: implement reference to 'ptr' field of slice '{}'", |
| 10900 | "TODO: implement reference to 'ptr' field of slice '{}'", | 10912 | .{inner_ty}, |
| 10901 | .{object_ty}, | 10913 | ); |
| 10902 | ); | 10914 | } else if (mem.eql(u8, field_name, "len")) { |
| 10903 | } else if (mem.eql(u8, field_name, "len")) { | 10915 | return sema.fail( |
| 10904 | return sema.fail( | 10916 | block, |
| 10905 | block, | 10917 | field_name_src, |
| 10906 | field_name_src, | 10918 | "TODO: implement reference to 'len' field of slice '{}'", |
| 10907 | "TODO: implement reference to 'len' field of slice '{}'", | 10919 | .{inner_ty}, |
| 10908 | .{object_ty}, | 10920 | ); |
| 10909 | ); | 10921 | } else { |
| 10910 | } else { | 10922 | return sema.fail( |
| 10911 | return sema.fail( | 10923 | block, |
| 10912 | block, | 10924 | field_name_src, |
| 10913 | field_name_src, | 10925 | "no member named '{s}' in '{}'", |
| 10914 | "no member named '{s}' in '{}'", | 10926 | .{ field_name, object_ty }, |
| 10915 | .{ field_name, object_ty }, | 10927 | ); |
| 10916 | ); | 10928 | } |
| 10917 | } | | |
| 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 => {}, | | |
| 10948 | } | | |
| 10949 | }, | | |
| 10950 | .Many, .C => {}, | | |
| 10951 | }, | 10929 | }, |
| 10952 | .Type => { | 10930 | .Type => { |
| 10953 | _ = try sema.resolveConstValue(block, object_ptr_src, object_ptr); | 10931 | _ = try sema.resolveConstValue(block, object_ptr_src, object_ptr); |
| 10954 | const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src); | 10932 | const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src); |
| 10955 | const val = (sema.resolveDefinedValue(block, src, result) catch unreachable).?; | 10933 | const inner = if (is_pointer_to) |
| | 10934 | try sema.analyzeLoad(block, src, result, object_ptr_src) |
| | 10935 | else |
| | 10936 | result; |
| | 10937 | |
| | 10938 | const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?; |
| 10956 | var to_type_buffer: Value.ToTypeBuffer = undefined; | 10939 | var to_type_buffer: Value.ToTypeBuffer = undefined; |
| 10957 | const child_type = val.toType(&to_type_buffer); | 10940 | const child_type = val.toType(&to_type_buffer); |
| | 10941 | |
| 10958 | switch (child_type.zigTypeTag()) { | 10942 | switch (child_type.zigTypeTag()) { |
| 10959 | .ErrorSet => { | 10943 | .ErrorSet => { |
| 10960 | // TODO resolve inferred error sets | 10944 | // TODO resolve inferred error sets |
| ... | @@ -11033,8 +11017,20 @@ fn fieldPtr( | ... | @@ -11033,8 +11017,20 @@ fn fieldPtr( |
| 11033 | else => return sema.fail(block, src, "type '{}' has no members", .{child_type}), | 11017 | else => return sema.fail(block, src, "type '{}' has no members", .{child_type}), |
| 11034 | } | 11018 | } |
| 11035 | }, | 11019 | }, |
| 11036 | .Struct => return sema.structFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty), | 11020 | .Struct => { |
| 11037 | .Union => return sema.unionFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty), | 11021 | const inner_ptr = if (is_pointer_to) |
| | 11022 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) |
| | 11023 | else |
| | 11024 | object_ptr; |
| | 11025 | return sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty); |
| | 11026 | }, |
| | 11027 | .Union => { |
| | 11028 | const inner_ptr = if (is_pointer_to) |
| | 11029 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) |
| | 11030 | else |
| | 11031 | object_ptr; |
| | 11032 | return sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty); |
| | 11033 | }, |
| 11038 | else => {}, | 11034 | else => {}, |
| 11039 | } | 11035 | } |
| 11040 | return sema.fail(block, src, "type '{}' does not support field access", .{object_ty}); | 11036 | return sema.fail(block, src, "type '{}' does not support field access", .{object_ty}); |