| ... | @@ -3378,26 +3378,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE | ... | @@ -3378,26 +3378,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 3378 | else | 3378 | else |
| 3379 | object_ty; | 3379 | object_ty; |
| 3380 | | 3380 | |
| 3381 | if (!array_ty.isIndexable()) { | 3381 | try checkIndexable(sema, block, src, array_ty); |
| 3382 | const msg = msg: { | | |
| 3383 | const msg = try sema.errMsg( | | |
| 3384 | block, | | |
| 3385 | src, | | |
| 3386 | "type '{}' does not support indexing", | | |
| 3387 | .{array_ty.fmt(sema.mod)}, | | |
| 3388 | ); | | |
| 3389 | errdefer msg.destroy(sema.gpa); | | |
| 3390 | try sema.errNote( | | |
| 3391 | block, | | |
| 3392 | src, | | |
| 3393 | msg, | | |
| 3394 | "for loop operand must be an array, slice, tuple, or vector", | | |
| 3395 | .{}, | | |
| 3396 | ); | | |
| 3397 | break :msg msg; | | |
| 3398 | }; | | |
| 3399 | return sema.failWithOwnedErrorMsg(msg); | | |
| 3400 | } | | |
| 3401 | | 3382 | |
| 3402 | return sema.fieldVal(block, src, object, "len", src); | 3383 | return sema.fieldVal(block, src, object, "len", src); |
| 3403 | } | 3384 | } |
| ... | @@ -3921,13 +3902,70 @@ fn zirFieldBasePtr( | ... | @@ -3921,13 +3902,70 @@ fn zirFieldBasePtr( |
| 3921 | } | 3902 | } |
| 3922 | | 3903 | |
| 3923 | fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 3904 | fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| | 3905 | const gpa = sema.gpa; |
| 3924 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3906 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 3925 | const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); | 3907 | const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); |
| 3926 | const args = sema.code.refSlice(extra.end, extra.data.operands_len); | 3908 | const args = sema.code.refSlice(extra.end, extra.data.operands_len); |
| 3927 | const src = inst_data.src(); | 3909 | const src = inst_data.src(); |
| 3928 | | 3910 | |
| 3929 | _ = args; | 3911 | var len: Air.Inst.Ref = .none; |
| 3930 | return sema.fail(block, src, "TODO implement zirForCheckLens", .{}); | 3912 | var len_val: ?Value = null; |
| | 3913 | var len_idx: usize = undefined; |
| | 3914 | var any_runtime = false; |
| | 3915 | |
| | 3916 | const runtime_arg_lens = try gpa.alloc(Air.Inst.Ref, args.len); |
| | 3917 | defer gpa.free(runtime_arg_lens); |
| | 3918 | |
| | 3919 | // First pass to look for comptime values. |
| | 3920 | for (args) |zir_arg, i| { |
| | 3921 | runtime_arg_lens[i] = .none; |
| | 3922 | if (zir_arg == .none) continue; |
| | 3923 | const object = try sema.resolveInst(zir_arg); |
| | 3924 | const object_ty = sema.typeOf(object); |
| | 3925 | // Each arg could be an indexable, or a range, in which case the length |
| | 3926 | // is passed directly as an integer. |
| | 3927 | const arg_len = if (object_ty.zigTypeTag() == .Int) object else l: { |
| | 3928 | try checkIndexable(sema, block, src, object_ty); |
| | 3929 | if (!object_ty.indexableHasLen()) continue; |
| | 3930 | |
| | 3931 | break :l try sema.fieldVal(block, src, object, "len", src); |
| | 3932 | }; |
| | 3933 | if (len == .none) { |
| | 3934 | len = arg_len; |
| | 3935 | len_idx = i; |
| | 3936 | } |
| | 3937 | if (try sema.resolveDefinedValue(block, src, arg_len)) |arg_val| { |
| | 3938 | if (len_val) |v| { |
| | 3939 | if (!(try sema.valuesEqual(arg_val, v, Type.usize))) { |
| | 3940 | // TODO error notes for each arg stating the differing values |
| | 3941 | return sema.fail(block, src, "non-matching for loop lengths", .{}); |
| | 3942 | } |
| | 3943 | } else { |
| | 3944 | len = arg_len; |
| | 3945 | len_val = arg_val; |
| | 3946 | len_idx = i; |
| | 3947 | } |
| | 3948 | continue; |
| | 3949 | } |
| | 3950 | runtime_arg_lens[i] = arg_len; |
| | 3951 | any_runtime = true; |
| | 3952 | } |
| | 3953 | |
| | 3954 | if (len == .none) { |
| | 3955 | return sema.fail(block, src, "non-obvious infinite loop", .{}); |
| | 3956 | } |
| | 3957 | |
| | 3958 | // Now for the runtime checks. |
| | 3959 | if (any_runtime and block.wantSafety()) { |
| | 3960 | for (runtime_arg_lens) |arg_len, i| { |
| | 3961 | if (arg_len == .none) continue; |
| | 3962 | if (i == len_idx) continue; |
| | 3963 | const ok = try block.addBinOp(.cmp_eq, len, arg_len); |
| | 3964 | try sema.addSafetyCheck(block, ok, .for_len_mismatch); |
| | 3965 | } |
| | 3966 | } |
| | 3967 | |
| | 3968 | return len; |
| 3931 | } | 3969 | } |
| 3932 | | 3970 | |
| 3933 | fn validateArrayInitTy( | 3971 | fn validateArrayInitTy( |
| ... | @@ -9655,7 +9693,7 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -9655,7 +9693,7 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9655 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 9693 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 9656 | const array_ptr = try sema.resolveInst(extra.lhs); | 9694 | const array_ptr = try sema.resolveInst(extra.lhs); |
| 9657 | const elem_index = try sema.resolveInst(extra.rhs); | 9695 | const elem_index = try sema.resolveInst(extra.rhs); |
| 9658 | return sema.elemPtr(block, src, array_ptr, elem_index, src, false); | 9696 | return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false); |
| 9659 | } | 9697 | } |
| 9660 | | 9698 | |
| 9661 | fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 9699 | fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -22687,6 +22725,7 @@ pub const PanicId = enum { | ... | @@ -22687,6 +22725,7 @@ pub const PanicId = enum { |
| 22687 | unwrap_error, | 22725 | unwrap_error, |
| 22688 | index_out_of_bounds, | 22726 | index_out_of_bounds, |
| 22689 | start_index_greater_than_end, | 22727 | start_index_greater_than_end, |
| | 22728 | for_len_mismatch, |
| 22690 | }; | 22729 | }; |
| 22691 | | 22730 | |
| 22692 | fn addSafetyCheck( | 22731 | fn addSafetyCheck( |
| ... | @@ -24076,21 +24115,46 @@ fn elemPtr( | ... | @@ -24076,21 +24115,46 @@ fn elemPtr( |
| 24076 | .Pointer => indexable_ptr_ty.elemType(), | 24115 | .Pointer => indexable_ptr_ty.elemType(), |
| 24077 | else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(sema.mod)}), | 24116 | else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(sema.mod)}), |
| 24078 | }; | 24117 | }; |
| | 24118 | switch (indexable_ty.zigTypeTag()) { |
| | 24119 | .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init), |
| | 24120 | .Struct => { |
| | 24121 | // Tuple field access. |
| | 24122 | const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known"); |
| | 24123 | const index = @intCast(u32, index_val.toUnsignedInt(target)); |
| | 24124 | return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init); |
| | 24125 | }, |
| | 24126 | else => { |
| | 24127 | const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); |
| | 24128 | return elemPtrOneLayerOnly(sema, block, src, indexable, elem_index, elem_index_src, init); |
| | 24129 | }, |
| | 24130 | } |
| | 24131 | } |
| | 24132 | |
| | 24133 | fn elemPtrOneLayerOnly( |
| | 24134 | sema: *Sema, |
| | 24135 | block: *Block, |
| | 24136 | src: LazySrcLoc, |
| | 24137 | indexable: Air.Inst.Ref, |
| | 24138 | elem_index: Air.Inst.Ref, |
| | 24139 | elem_index_src: LazySrcLoc, |
| | 24140 | init: bool, |
| | 24141 | ) CompileError!Air.Inst.Ref { |
| | 24142 | const indexable_src = src; // TODO better source location |
| | 24143 | const indexable_ty = sema.typeOf(indexable); |
| 24079 | if (!indexable_ty.isIndexable()) { | 24144 | if (!indexable_ty.isIndexable()) { |
| 24080 | return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty.fmt(sema.mod)}); | 24145 | return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty.fmt(sema.mod)}); |
| 24081 | } | 24146 | } |
| | 24147 | const target = sema.mod.getTarget(); |
| 24082 | | 24148 | |
| 24083 | switch (indexable_ty.zigTypeTag()) { | 24149 | switch (indexable_ty.zigTypeTag()) { |
| 24084 | .Pointer => { | 24150 | .Pointer => { |
| 24085 | // In all below cases, we have to deref the ptr operand to get the actual indexable pointer. | | |
| 24086 | const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); | | |
| 24087 | switch (indexable_ty.ptrSize()) { | 24151 | switch (indexable_ty.ptrSize()) { |
| 24088 | .Slice => return sema.elemPtrSlice(block, src, indexable_ptr_src, indexable, elem_index_src, elem_index), | 24152 | .Slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index), |
| 24089 | .Many, .C => { | 24153 | .Many, .C => { |
| 24090 | const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_ptr_src, indexable); | 24154 | const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable); |
| 24091 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); | 24155 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 24092 | const runtime_src = rs: { | 24156 | const runtime_src = rs: { |
| 24093 | const ptr_val = maybe_ptr_val orelse break :rs indexable_ptr_src; | 24157 | const ptr_val = maybe_ptr_val orelse break :rs indexable_src; |
| 24094 | const index_val = maybe_index_val orelse break :rs elem_index_src; | 24158 | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 24095 | const index = @intCast(usize, index_val.toUnsignedInt(target)); | 24159 | const index = @intCast(usize, index_val.toUnsignedInt(target)); |
| 24096 | const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, sema.mod); | 24160 | const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, sema.mod); |
| ... | @@ -24104,18 +24168,16 @@ fn elemPtr( | ... | @@ -24104,18 +24168,16 @@ fn elemPtr( |
| 24104 | }, | 24168 | }, |
| 24105 | .One => { | 24169 | .One => { |
| 24106 | assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable | 24170 | assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable |
| 24107 | return sema.elemPtrArray(block, src, indexable_ptr_src, indexable, elem_index_src, elem_index, init); | 24171 | return sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init); |
| 24108 | }, | 24172 | }, |
| 24109 | } | 24173 | } |
| 24110 | }, | 24174 | }, |
| 24111 | .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init), | 24175 | else => { |
| 24112 | .Struct => { | 24176 | // TODO add note pointing at corresponding for loop input and suggest using '&' |
| 24113 | // Tuple field access. | 24177 | return sema.fail(block, indexable_src, "pointer capture of non pointer type '{}'", .{ |
| 24114 | const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known"); | 24178 | indexable_ty.fmt(sema.mod), |
| 24115 | const index = @intCast(u32, index_val.toUnsignedInt(target)); | 24179 | }); |
| 24116 | return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init); | | |
| 24117 | }, | 24180 | }, |
| 24118 | else => unreachable, | | |
| 24119 | } | 24181 | } |
| 24120 | } | 24182 | } |
| 24121 | | 24183 | |
| ... | @@ -30202,6 +30264,29 @@ fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ | ... | @@ -30202,6 +30264,29 @@ fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ |
| 30202 | } | 30264 | } |
| 30203 | } | 30265 | } |
| 30204 | | 30266 | |
| | 30267 | fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, array_ty: Type) !void { |
| | 30268 | if (!array_ty.isIndexable()) { |
| | 30269 | const msg = msg: { |
| | 30270 | const msg = try sema.errMsg( |
| | 30271 | block, |
| | 30272 | src, |
| | 30273 | "type '{}' does not support indexing", |
| | 30274 | .{array_ty.fmt(sema.mod)}, |
| | 30275 | ); |
| | 30276 | errdefer msg.destroy(sema.gpa); |
| | 30277 | try sema.errNote( |
| | 30278 | block, |
| | 30279 | src, |
| | 30280 | msg, |
| | 30281 | "for loop operand must be an array, slice, tuple, or vector", |
| | 30282 | .{}, |
| | 30283 | ); |
| | 30284 | break :msg msg; |
| | 30285 | }; |
| | 30286 | return sema.failWithOwnedErrorMsg(msg); |
| | 30287 | } |
| | 30288 | } |
| | 30289 | |
| 30205 | fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { | 30290 | fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { |
| 30206 | const resolved_ty = try sema.resolveTypeFields(ty); | 30291 | const resolved_ty = try sema.resolveTypeFields(ty); |
| 30207 | const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; | 30292 | const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; |