diff --git a/src/AstGen.zig b/src/AstGen.zig index 7d3a165d2f..523ac235ac 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -88,6 +88,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void { Zir.Inst.BuiltinCall.Flags => @bitCast(u32, @field(extra, field.name)), Zir.Inst.SwitchBlock.Bits => @bitCast(u32, @field(extra, field.name)), Zir.Inst.FuncFancy.Bits => @bitCast(u32, @field(extra, field.name)), + Zir.Inst.ElemPtrImm.Bits => @bitCast(u32, @field(extra, field.name)), else => @compileError("bad field type"), }; i += 1; @@ -1565,7 +1566,9 @@ fn arrayInitExprRlPtrInner( for (elements) |elem_init, i| { const elem_ptr = try gz.addPlNode(.elem_ptr_imm, elem_init, Zir.Inst.ElemPtrImm{ .ptr = result_ptr, - .index = @intCast(u32, i), + .bits = .{ + .index = @intCast(u31, i), + }, }); astgen.extra.items[extra_index] = refToIndex(elem_ptr).?; extra_index += 1; @@ -6308,7 +6311,7 @@ fn forExpr( const lens = try gpa.alloc(Zir.Inst.Ref, for_full.ast.inputs.len); defer gpa.free(lens); - const counter_alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime_mut else .alloc; + const alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime_mut else .alloc_mut; // Tracks the index of allocs/lens that has a length to be checked and is // used for the end value. @@ -6321,23 +6324,24 @@ fn forExpr( var cond_end_val: Zir.Inst.Ref = .none; { - var payload = for_full.payload_token; + var capture_token = for_full.payload_token; for (for_full.ast.inputs) |input, i_usize| { const i = @intCast(u32, i_usize); - const payload_is_ref = token_tags[payload] == .asterisk; - const ident_tok = payload + @boolToInt(payload_is_ref); + const capture_is_ref = token_tags[capture_token] == .asterisk; + const ident_tok = capture_token + @boolToInt(capture_is_ref); - if (mem.eql(u8, tree.tokenSlice(ident_tok), "_") and payload_is_ref) { - return astgen.failTok(payload, "pointer modifier invalid on discard", .{}); + if (mem.eql(u8, tree.tokenSlice(ident_tok), "_") and capture_is_ref) { + return astgen.failTok(capture_token, "pointer modifier invalid on discard", .{}); } - payload = ident_tok + @as(u32, 2); + // Skip over the comma, and on to the next capture (or the ending pipe character). + capture_token = ident_tok + 2; try emitDbgNode(parent_gz, input); if (node_tags[input] == .for_range) { - if (payload_is_ref) { + if (capture_is_ref) { return astgen.failTok(ident_tok, "cannot capture reference to range", .{}); } - const counter_ptr = try parent_gz.addUnNode(counter_alloc_tag, .usize_type, node); + const counter_ptr = try parent_gz.addUnNode(alloc_tag, .usize_type, node); const start_node = node_data[input].lhs; const start_val = try expr(parent_gz, scope, .{ .rl = .none }, start_node); _ = try parent_gz.addBin(.store, counter_ptr, start_val); @@ -6364,20 +6368,28 @@ fn forExpr( allocs[i] = counter_ptr; lens[i] = range_len; } else { - const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none }; - const indexable = try expr(parent_gz, scope, cond_ri, input); + const indexable = try expr(parent_gz, scope, .{ .rl = .none }, input); + // This instruction has nice compile errors so we put it before the other ones + // even though it is not needed until later in the block. + const ptr_len = try parent_gz.addUnNode(.indexable_ptr_len, indexable, input); const base_ptr = try parent_gz.addPlNode(.elem_ptr_imm, input, Zir.Inst.ElemPtrImm{ .ptr = indexable, - .index = 0, + .bits = .{ + .index = 0, + .manyptr = true, + }, }); + const alloc_ty_inst = try parent_gz.addUnNode(.typeof, base_ptr, node); + const alloc = try parent_gz.addUnNode(alloc_tag, alloc_ty_inst, node); + _ = try parent_gz.addBin(.store, alloc, base_ptr); if (end_input_index == null) { end_input_index = i; assert(cond_end_val == .none); } - allocs[i] = base_ptr; - lens[i] = try parent_gz.addUnNode(.indexable_ptr_len, indexable, input); + allocs[i] = alloc; + lens[i] = ptr_len; } } } @@ -6467,62 +6479,47 @@ fn forExpr( var then_scope = parent_gz.makeSubBlock(&cond_scope.base); defer then_scope.unstack(); - const then_sub_scope = &then_scope.base; + try then_scope.addDbgBlockBegin(); - // try then_scope.addDbgBlockBegin(); - // var payload_val_scope: Scope.LocalVal = undefined; - // var index_scope: Scope.LocalPtr = undefined; - // const then_sub_scope = blk: { - // const payload_token = for_full.payload_token.?; - // const ident = if (token_tags[payload_token] == .asterisk) - // payload_token + 1 - // else - // payload_token; - // const is_ptr = ident != payload_token; - // const value_name = tree.tokenSlice(ident); - // var payload_sub_scope: *Scope = undefined; - // if (!mem.eql(u8, value_name, "_")) { - // const name_str_index = try astgen.identAsString(ident); - // const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val; - // const payload_inst = try then_scope.addPlNode(tag, for_full.ast.cond_expr, Zir.Inst.Bin{ - // .lhs = array_ptr, - // .rhs = index, - // }); - // try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name, .capture); - // payload_val_scope = .{ - // .parent = &then_scope.base, - // .gen_zir = &then_scope, - // .name = name_str_index, - // .inst = payload_inst, - // .token_src = ident, - // .id_cat = .capture, - // }; - // try then_scope.addDbgVar(.dbg_var_val, name_str_index, payload_inst); - // payload_sub_scope = &payload_val_scope.base; - // } else if (is_ptr) { - // } else { - // payload_sub_scope = &then_scope.base; - // } + const capture_scopes = try gpa.alloc(Scope.LocalVal, for_full.ast.inputs.len); + defer gpa.free(capture_scopes); - // const index_token = if (token_tags[ident + 1] == .comma) - // ident + 2 - // else - // break :blk payload_sub_scope; - // const token_bytes = tree.tokenSlice(index_token); - // const index_name = try astgen.identAsString(index_token); - // try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes, .@"loop index capture"); - // index_scope = .{ - // .parent = payload_sub_scope, - // .gen_zir = &then_scope, - // .name = index_name, - // .ptr = index_ptr, - // .token_src = index_token, - // .maybe_comptime = is_inline, - // .id_cat = .@"loop index capture", - // }; - // try then_scope.addDbgVar(.dbg_var_val, index_name, index_ptr); - // break :blk &index_scope.base; - // }; + const then_sub_scope = blk: { + var capture_token = for_full.payload_token; + var capture_sub_scope: *Scope = &then_scope.base; + for (for_full.ast.inputs) |input, i_usize| { + const i = @intCast(u32, i_usize); + const capture_is_ref = token_tags[capture_token] == .asterisk; + const ident_tok = capture_token + @boolToInt(capture_is_ref); + const capture_name = tree.tokenSlice(ident_tok); + // Skip over the comma, and on to the next capture (or the ending pipe character). + capture_token = ident_tok + 2; + + if (mem.eql(u8, capture_name, "_")) continue; + + const name_str_index = try astgen.identAsString(ident_tok); + try astgen.detectLocalShadowing(capture_sub_scope, name_str_index, ident_tok, capture_name, .capture); + + const loaded = if (capture_is_ref) + loaded_ptrs[i] + else + try then_scope.addUnNode(.load, loaded_ptrs[i], input); + + capture_scopes[i] = .{ + .parent = capture_sub_scope, + .gen_zir = &then_scope, + .name = name_str_index, + .inst = loaded, + .token_src = ident_tok, + .id_cat = .capture, + }; + + try then_scope.addDbgVar(.dbg_var_val, name_str_index, loaded); + capture_sub_scope = &capture_scopes[i].base; + } + + break :blk capture_sub_scope; + }; const then_result = try expr(&then_scope, then_sub_scope, .{ .rl = .none }, for_full.ast.then_expr); _ = try addEnsureResult(&then_scope, then_result, for_full.ast.then_expr); diff --git a/src/Sema.zig b/src/Sema.zig index b5afe93511..c251aa9fbf 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -9649,7 +9649,7 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const array_ptr = try sema.resolveInst(extra.lhs); const elem_index = try sema.resolveInst(extra.rhs); - return sema.elemPtr(block, src, array_ptr, elem_index, src, false); + return sema.elemPtr(block, src, array_ptr, elem_index, src, false, .One); } fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -9662,7 +9662,7 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const array_ptr = try sema.resolveInst(extra.lhs); const elem_index = try sema.resolveInst(extra.rhs); - return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false); + return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false, .One); } fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -9673,8 +9673,9 @@ fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const src = inst_data.src(); const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data; const array_ptr = try sema.resolveInst(extra.ptr); - const elem_index = try sema.addIntUnsigned(Type.usize, extra.index); - return sema.elemPtr(block, src, array_ptr, elem_index, src, true); + const elem_index = try sema.addIntUnsigned(Type.usize, extra.bits.index); + const size: std.builtin.Type.Pointer.Size = if (extra.bits.manyptr) .Many else .One; + return sema.elemPtr(block, src, array_ptr, elem_index, src, true, size); } fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -22905,7 +22906,7 @@ fn panicSentinelMismatch( const actual_sentinel = if (ptr_ty.isSlice()) try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index) else blk: { - const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null); + const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null, .One); const sentinel_ptr = try parent_block.addPtrElemPtr(ptr, sentinel_index, elem_ptr_ty); break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr); }; @@ -24072,6 +24073,7 @@ fn elemPtr( elem_index: Air.Inst.Ref, elem_index_src: LazySrcLoc, init: bool, + size: std.builtin.Type.Pointer.Size, ) CompileError!Air.Inst.Ref { const indexable_ptr_src = src; // TODO better source location const indexable_ptr_ty = sema.typeOf(indexable_ptr); @@ -24098,13 +24100,12 @@ fn elemPtr( const index_val = maybe_index_val orelse break :rs elem_index_src; const index = @intCast(usize, index_val.toUnsignedInt(target)); const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, sema.mod); - const result_ty = try sema.elemPtrType(indexable_ty, index); - return sema.addConstant(result_ty, elem_ptr); + const elem_ptr_ty = try sema.elemPtrType(indexable_ty, index, size); + return sema.addConstant(elem_ptr_ty, elem_ptr); }; - const result_ty = try sema.elemPtrType(indexable_ty, null); - + const elem_ptr_ty = try sema.elemPtrType(indexable_ty, null, size); try sema.requireRuntimeBlock(block, src, runtime_src); - return block.addPtrElemPtr(indexable, elem_index, result_ty); + return block.addPtrElemPtr(indexable, elem_index, elem_ptr_ty); }, .One => { assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable @@ -24166,7 +24167,7 @@ fn elemVal( }, .One => { assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable - const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false); + const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, .One); return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src); }, }, @@ -24404,7 +24405,7 @@ fn elemPtrArray( break :o index; } else null; - const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset); + const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset, .One); if (maybe_undef_array_ptr_val) |array_ptr_val| { if (array_ptr_val.isUndef()) { @@ -24509,7 +24510,7 @@ fn elemPtrSlice( break :o index; } else null; - const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset); + const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset, .One); if (maybe_undef_slice_val) |slice_val| { if (slice_val.isUndef()) { @@ -26239,7 +26240,7 @@ fn storePtr2( const elem_src = operand_src; // TODO better source location const elem = try sema.tupleField(block, operand_src, uncasted_operand, elem_src, i); const elem_index = try sema.addIntUnsigned(Type.usize, i); - const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false); + const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false, .One); try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store); } return; @@ -33276,7 +33277,12 @@ fn compareVector( /// For []T, returns *T /// Handles const-ness and address spaces in particular. /// This code is duplicated in `analyzePtrArithmetic`. -fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { +fn elemPtrType( + sema: *Sema, + ptr_ty: Type, + offset: ?usize, + size: std.builtin.Type.Pointer.Size, +) !Type { const ptr_info = ptr_ty.ptrInfo().data; const elem_ty = ptr_ty.elemType2(); const allow_zero = ptr_info.@"allowzero" and (offset orelse 0) == 0; @@ -33321,6 +33327,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { break :a new_align; }; return try Type.ptr(sema.arena, sema.mod, .{ + .size = size, .pointee_type = elem_ty, .mutable = ptr_info.mutable, .@"addrspace" = ptr_info.@"addrspace", diff --git a/src/Zir.zig b/src/Zir.zig index de6c2f02d1..edbd70e170 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -79,6 +79,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, en Inst.BuiltinCall.Flags => @bitCast(Inst.BuiltinCall.Flags, code.extra[i]), Inst.SwitchBlock.Bits => @bitCast(Inst.SwitchBlock.Bits, code.extra[i]), Inst.FuncFancy.Bits => @bitCast(Inst.FuncFancy.Bits, code.extra[i]), + Inst.ElemPtrImm.Bits => @bitCast(Inst.ElemPtrImm.Bits, code.extra[i]), else => @compileError("bad field type"), }; i += 1; @@ -388,6 +389,8 @@ pub const Inst = struct { /// as a reference to another ZIR instruction. /// Uses the `pl_node` union field. AST node is an element inside array initialization /// syntax. Payload is `ElemPtrImm`. + /// This instruction has a way to set the result type to be a + /// single-pointer or a many-pointer. elem_ptr_imm, /// Given an array, slice, or pointer, returns the element at the provided index. /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`. @@ -2972,7 +2975,13 @@ pub const Inst = struct { pub const ElemPtrImm = struct { ptr: Ref, - index: u32, + bits: Bits, + + pub const Bits = packed struct(u32) { + index: u31, + /// Controls whether the type returned is `*T` or `[*]T`. + manyptr: bool = false, + }; }; /// 0. multi_cases_len: u32 // If has_multi_cases is set. diff --git a/src/print_zir.zig b/src/print_zir.zig index f2436f7679..0977a88d53 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -888,7 +888,9 @@ const Writer = struct { const extra = self.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data; try self.writeInstRef(stream, extra.ptr); - try stream.print(", {d}) ", .{extra.index}); + try stream.print(", {d}", .{extra.bits.index}); + try self.writeFlag(stream, ", manyptr", extra.bits.manyptr); + try stream.writeAll(") "); try self.writeSrc(stream, inst_data.src()); }