diff --git a/src/AstGen.zig b/src/AstGen.zig index ba27165cea..ec1cae7386 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1273,16 +1273,8 @@ fn arrayInitExpr( assert(array_init.ast.elements.len != 0); // Otherwise it would be struct init. - const types: struct { - array: Zir.Inst.Ref, - elem: Zir.Inst.Ref, - sentinel: Zir.Inst.Ref, - } = inst: { - if (array_init.ast.type_expr == 0) break :inst .{ - .array = .none, - .elem = .none, - .sentinel = .none, - }; + const array_ty: Zir.Inst.Ref = inst: { + if (array_init.ast.type_expr == 0) break :inst .none; infer: { const array_type: Ast.full.ArrayType = switch (node_tags[array_init.ast.type_expr]) { @@ -1297,15 +1289,10 @@ fn arrayInitExpr( const len_inst = try gz.addInt(array_init.ast.elements.len); const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type); if (array_type.ast.sentinel == 0) { - const array_type_inst = try gz.addBin(.array_type, len_inst, elem_type); - break :inst .{ - .array = array_type_inst, - .elem = elem_type, - .sentinel = .none, - }; + break :inst try gz.addBin(.array_type, len_inst, elem_type); } else { const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel); - const array_type_inst = try gz.addPlNode( + break :inst try gz.addPlNode( .array_type_sentinel, array_init.ast.type_expr, Zir.Inst.ArrayTypeSentinel{ @@ -1314,76 +1301,57 @@ fn arrayInitExpr( .sentinel = sentinel, }, ); - break :inst .{ - .array = array_type_inst, - .elem = elem_type, - .sentinel = sentinel, - }; } } } const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr); _ = try gz.addUnNode(.validate_array_init_ty, array_type_inst, node); - const elem_type = try gz.addUnNode(.elem_type, array_type_inst, array_init.ast.type_expr); - break :inst .{ - .array = array_type_inst, - .elem = elem_type, - .sentinel = .none, - }; + break :inst array_type_inst; }; switch (rl) { .discard => { + // TODO elements should still be coerced if type is provided for (array_init.ast.elements) |elem_init| { _ = try expr(gz, scope, .discard, elem_init); } return Zir.Inst.Ref.void_value; }, .ref => { - if (types.array != .none) { - return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, true); - } else { - return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref); - } + const tag: Zir.Inst.Tag = if (array_ty != .none) .array_init_ref else .array_init_anon_ref; + return arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, tag); }, .none => { - if (types.array != .none) { - return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false); - } else { - return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); - } + const tag: Zir.Inst.Tag = if (array_ty != .none) .array_init else .array_init_anon; + return arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, tag); }, .ty, .coerced_ty => { - if (types.array != .none) { - const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false); - return rvalue(gz, rl, result, node); - } else { - const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); - return rvalue(gz, rl, result, node); - } + const tag: Zir.Inst.Tag = if (array_ty != .none) .array_init else .array_init_anon; + const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, tag); + return rvalue(gz, rl, result, node); }, .ptr => |ptr_inst| { - return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, types.array); + return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, array_ty); }, .inferred_ptr => |ptr_inst| { - if (types.array == .none) { + if (array_ty == .none) { // We treat this case differently so that we don't get a crash when // analyzing array_base_ptr against an alloc_inferred_mut. // See corresponding logic in structInitExpr. const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); return rvalue(gz, rl, result, node); } else { - return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, types.array); + return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, array_ty); } }, .block_ptr => |block_gz| { // This condition is here for the same reason as the above condition in `inferred_ptr`. // See corresponding logic in structInitExpr. - if (types.array == .none and astgen.isInferred(block_gz.rl_ptr)) { + if (array_ty == .none and astgen.isInferred(block_gz.rl_ptr)) { const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); return rvalue(gz, rl, result, node); } - return arrayInitExprRlPtr(gz, scope, rl, node, block_gz.rl_ptr, array_init.ast.elements, types.array); + return arrayInitExprRlPtr(gz, scope, rl, node, block_gz.rl_ptr, array_init.ast.elements, array_ty); }, } } @@ -1410,52 +1378,33 @@ fn arrayInitExprRlNone( return try gz.addPlNodePayloadIndex(tag, node, payload_index); } -fn arrayInitExprRlTy( +fn arrayInitExprInner( gz: *GenZir, scope: *Scope, node: Ast.Node.Index, elements: []const Ast.Node.Index, - elem_ty_inst: Zir.Inst.Ref, - sentinel: Zir.Inst.Ref, - ref: bool, + array_ty_inst: Zir.Inst.Ref, + tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const info: struct { - len: usize, - tag: Zir.Inst.Tag, - } = blk: { - if (sentinel != .none) { - break :blk .{ - .len = elements.len + 1, - .tag = if (ref) .array_init_sent_ref else .array_init_sent, - }; - } else { - break :blk .{ - .len = elements.len, - .tag = if (ref) .array_init_ref else .array_init, - }; - } - }; - + const len = elements.len + @boolToInt(array_ty_inst != .none); const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{ - .operands_len = @intCast(u32, info.len), + .operands_len = @intCast(u32, len), }); - var extra_index = try reserveExtra(astgen, info.len); + var extra_index = try reserveExtra(astgen, len); + if (array_ty_inst != .none) { + astgen.extra.items[extra_index] = @enumToInt(array_ty_inst); + extra_index += 1; + } - const elem_rl: ResultLoc = .{ .ty = elem_ty_inst }; for (elements) |elem_init| { - const elem_ref = try expr(gz, scope, elem_rl, elem_init); + const elem_ref = try expr(gz, scope, .none, elem_init); astgen.extra.items[extra_index] = @enumToInt(elem_ref); extra_index += 1; } - if (sentinel != .none) { - astgen.extra.items[extra_index] = @enumToInt(sentinel); - extra_index += 1; - } - - return try gz.addPlNodePayloadIndex(info.tag, node, payload_index); + return try gz.addPlNodePayloadIndex(tag, node, payload_index); } fn arrayInitExprRlPtr( @@ -2244,7 +2193,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner .array_type, .array_type_sentinel, .vector_type, - .elem_type, .indexable_ptr_len, .anyframe_type, .as, @@ -2347,10 +2295,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner .struct_init_anon_ref, .array_init, .array_init_anon, - .array_init_sent, .array_init_ref, .array_init_anon_ref, - .array_init_sent_ref, .union_init, .field_type, .field_type_ref, diff --git a/src/Sema.zig b/src/Sema.zig index e0310e5ad7..2a5b3e0260 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -726,7 +726,6 @@ fn analyzeBodyInner( .elem_ptr_imm => try sema.zirElemPtrImm(block, inst), .elem_val => try sema.zirElemVal(block, inst), .elem_val_node => try sema.zirElemValNode(block, inst), - .elem_type => try sema.zirElemType(block, inst), .enum_literal => try sema.zirEnumLiteral(block, inst), .enum_to_int => try sema.zirEnumToInt(block, inst), .int_to_enum => try sema.zirIntToEnum(block, inst), @@ -798,10 +797,8 @@ fn analyzeBodyInner( .struct_init_ref => try sema.zirStructInit(block, inst, true), .struct_init_anon => try sema.zirStructInitAnon(block, inst, false), .struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true), - .array_init => try sema.zirArrayInit(block, inst, false, false), - .array_init_sent => try sema.zirArrayInit(block, inst, false, true), - .array_init_ref => try sema.zirArrayInit(block, inst, true, false), - .array_init_sent_ref => try sema.zirArrayInit(block, inst, true, true), + .array_init => try sema.zirArrayInit(block, inst, false), + .array_init_ref => try sema.zirArrayInit(block, inst, true), .array_init_anon => try sema.zirArrayInitAnon(block, inst, false), .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true), .union_init => try sema.zirUnionInit(block, inst), @@ -13436,7 +13433,6 @@ fn zirArrayInit( block: *Block, inst: Zir.Inst.Index, is_ref: bool, - is_sent: bool, ) CompileError!Air.Inst.Ref { const gpa = sema.gpa; const inst_data = sema.code.instructions.items(.data)[inst].pl_node; @@ -13444,30 +13440,23 @@ fn zirArrayInit( const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); const args = sema.code.refSlice(extra.end, extra.data.operands_len); - assert(args.len != 0); + assert(args.len >= 2); // array_ty + at least one element - const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len); + const array_ty = try sema.resolveType(block, src, args[0]); + const sentinel_val = array_ty.sentinel(); + + const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @boolToInt(sentinel_val != null)); defer gpa.free(resolved_args); + const elem_ty = array_ty.elemType2(); + for (args[1..]) |arg, i| { + const resolved_arg = try sema.resolveInst(arg); + const arg_src = src; // TODO better source location + resolved_args[i] = try sema.coerce(block, elem_ty, resolved_arg, arg_src); + } - for (args) |arg, i| resolved_args[i] = try sema.resolveInst(arg); - - const elem_ty = sema.typeOf(resolved_args[0]); - const array_ty = blk: { - if (!is_sent) { - break :blk try Type.Tag.array.create(sema.arena, .{ - .len = resolved_args.len, - .elem_type = elem_ty, - }); - } - - const sentinel_ref = resolved_args[resolved_args.len - 1]; - const val = try sema.resolveConstValue(block, src, sentinel_ref); - break :blk try Type.Tag.array_sentinel.create(sema.arena, .{ - .len = resolved_args.len - 1, - .sentinel = val, - .elem_type = elem_ty, - }); - }; + if (sentinel_val) |some| { + resolved_args[resolved_args.len - 1] = try sema.addConstant(elem_ty, some); + } const opt_runtime_src: ?LazySrcLoc = for (resolved_args) |arg| { const arg_src = src; // TODO better source location @@ -13488,7 +13477,7 @@ fn zirArrayInit( }; try sema.requireRuntimeBlock(block, runtime_src); - try sema.queueFullTypeResolution(elem_ty); + try sema.queueFullTypeResolution(array_ty); if (is_ref) { const target = sema.mod.getTarget(); diff --git a/src/Zir.zig b/src/Zir.zig index c722457303..84e52a2e07 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -221,9 +221,6 @@ pub const Inst = struct { /// Uses the `pl_node` union field with `Bin` payload. /// lhs is length, rhs is element type. vector_type, - /// Given an array type, returns the element type. - /// Uses the `un_node` union field. - elem_type, /// Given a pointer to an indexable object, returns the len property. This is /// used by for loops. This instruction also emits a for-loop specific compile /// error if the indexable object is not indexable. @@ -737,20 +734,12 @@ pub const Inst = struct { /// Array initialization syntax. /// Uses the `pl_node` field. Payload is `MultiOp`. array_init, - /// Array initialization with sentinel. - /// Uses the `pl_node` field. Payload is `MultiOp`. - /// Final op in MultiOp is the sentinel. - array_init_sent, /// Anonymous array initialization syntax. /// Uses the `pl_node` field. Payload is `MultiOp`. array_init_anon, /// Array initialization syntax, make the result a pointer. /// Uses the `pl_node` field. Payload is `MultiOp`. array_init_ref, - /// Array initialization with sentinel. - /// Uses the `pl_node` field. Payload is `MultiOp`. - /// Final op in MultiOp is the sentinel. - array_init_sent_ref, /// Anonymous array initialization syntax, make the result a pointer. /// Uses the `pl_node` field. Payload is `MultiOp`. array_init_anon_ref, @@ -1019,7 +1008,6 @@ pub const Inst = struct { .array_type, .array_type_sentinel, .vector_type, - .elem_type, .indexable_ptr_len, .anyframe_type, .as, @@ -1153,10 +1141,8 @@ pub const Inst = struct { .struct_init_anon, .struct_init_anon_ref, .array_init, - .array_init_sent, .array_init_anon, .array_init_ref, - .array_init_sent_ref, .array_init_anon_ref, .union_init, .field_type, @@ -1314,7 +1300,6 @@ pub const Inst = struct { .array_type, .array_type_sentinel, .vector_type, - .elem_type, .indexable_ptr_len, .anyframe_type, .as, @@ -1426,10 +1411,8 @@ pub const Inst = struct { .struct_init_anon, .struct_init_anon_ref, .array_init, - .array_init_sent, .array_init_anon, .array_init_ref, - .array_init_sent_ref, .array_init_anon_ref, .union_init, .field_type, @@ -1554,7 +1537,6 @@ pub const Inst = struct { .array_type = .bin, .array_type_sentinel = .pl_node, .vector_type = .pl_node, - .elem_type = .un_node, .indexable_ptr_len = .un_node, .anyframe_type = .un_node, .as = .bin, @@ -1688,10 +1670,8 @@ pub const Inst = struct { .struct_init_anon = .pl_node, .struct_init_anon_ref = .pl_node, .array_init = .pl_node, - .array_init_sent = .pl_node, .array_init_anon = .pl_node, .array_init_ref = .pl_node, - .array_init_sent_ref = .pl_node, .array_init_anon_ref = .pl_node, .union_init = .pl_node, .type_info = .un_node, diff --git a/src/print_zir.zig b/src/print_zir.zig index 1f243acc30..0d6681da05 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -226,7 +226,6 @@ const Writer = struct { .pop_count, .byte_swap, .bit_reverse, - .elem_type, .@"resume", .@"await", .switch_cond, @@ -268,10 +267,6 @@ const Writer = struct { .array_init_anon_ref, => try self.writeArrayInit(stream, inst), - .array_init_sent, - .array_init_sent_ref, - => try self.writeArrayInitSent(stream, inst), - .slice_start => try self.writeSliceStart(stream, inst), .slice_end => try self.writeSliceEnd(stream, inst), .slice_sentinel => try self.writeSliceSentinel(stream, inst), @@ -2085,8 +2080,9 @@ const Writer = struct { const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); const args = self.code.refSlice(extra.end, extra.data.operands_len); - try stream.writeAll(".{"); - for (args) |arg, i| { + try self.writeInstRef(stream, args[0]); + try stream.writeAll("{"); + for (args[1..]) |arg, i| { if (i != 0) try stream.writeAll(", "); try self.writeInstRef(stream, arg); } diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index ac9e776c76..11ecf089c5 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -942,3 +942,10 @@ test "comptime int in switch in catch is casted to correct inferred type" { }; _ = b; } + +test "vector initialized with array init syntax has proper type" { + comptime { + const actual = -@Vector(4, i32){ 1, 2, 3, 4 }; + try std.testing.expectEqual(@Vector(4, i32){ -1, -2, -3, -4 }, actual); + } +} diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index 5e044abf4f..f9237bb230 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -194,8 +194,6 @@ test "tuple as the result from a labeled block" { } test "initializing tuple with explicit type" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO - const T = @TypeOf(.{ @as(i32, 0), @as(u32, 0) }); var a = T{ 0, 0 }; _ = a;