diff options
| author | Veikka Tuominen <git@vexu.eu> | 2022-02-19 11:35:49 +0200 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-02-19 20:21:19 +0200 |
| commit | e02749224357a33cffcaf9970d14c199adc3d892 (patch) | |
| tree | 90970730e6d00583eeb8789e035d1f1dd8edc466 /src | |
| parent | 2f0204aca303daf899a97c740719a62398adc206 (diff) | |
| download | zig-e02749224357a33cffcaf9970d14c199adc3d892.tar.gz zig-e02749224357a33cffcaf9970d14c199adc3d892.zip | |
stage2: support anon init through error unions and optionals
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 9 | ||||
| -rw-r--r-- | src/Sema.zig | 109 | ||||
| -rw-r--r-- | src/Zir.zig | 16 | ||||
| -rw-r--r-- | src/print_zir.zig | 2 |
4 files changed, 122 insertions, 14 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index 0652a6232f..8f34a58ed4 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1384,7 +1384,8 @@ fn arrayInitExprRlPtr( array_ty: Zir.Inst.Ref, ) InnerError!Zir.Inst.Ref { if (array_ty == .none) { - return arrayInitExprRlPtrInner(gz, scope, node, result_ptr, elements); + const base_ptr = try gz.addUnNode(.array_base_ptr, result_ptr, node); + return arrayInitExprRlPtrInner(gz, scope, node, base_ptr, elements); } var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr); @@ -1493,6 +1494,7 @@ fn structInitExpr( switch (rl) { .discard => { + // TODO if a type expr is given the fields should be validated for that type if (struct_init.ast.type_expr != 0) _ = try typeExpr(gz, scope, struct_init.ast.type_expr); for (struct_init.ast.fields) |field_init| { @@ -1567,7 +1569,8 @@ fn structInitExprRlPtr( result_ptr: Zir.Inst.Ref, ) InnerError!Zir.Inst.Ref { if (struct_init.ast.type_expr == 0) { - return structInitExprRlPtrInner(gz, scope, node, struct_init, result_ptr); + const base_ptr = try gz.addUnNode(.field_base_ptr, result_ptr, node); + return structInitExprRlPtrInner(gz, scope, node, struct_init, base_ptr); } const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); @@ -2281,6 +2284,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner .ret_err_value_code, .extended, .closure_get, + .array_base_ptr, + .field_base_ptr, => break :b false, // ZIR instructions that are always `noreturn`. diff --git a/src/Sema.zig b/src/Sema.zig index 38cfb63f27..acccc0e3bf 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -739,6 +739,8 @@ fn analyzeBodyInner( .@"await" => try sema.zirAwait(block, inst, false), .await_nosuspend => try sema.zirAwait(block, inst, true), .extended => try sema.zirExtended(block, inst), + .array_base_ptr => try sema.zirArrayBasePtr(block, inst), + .field_base_ptr => try sema.zirFieldBasePtr(block, inst), .clz => try sema.zirBitCount(block, inst, .clz, Value.clz), .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz), @@ -2584,6 +2586,59 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com } } +fn zirArrayBasePtr( + sema: *Sema, + block: *Block, + inst: Zir.Inst.Index, +) CompileError!Air.Inst.Ref { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + + const start_ptr = sema.resolveInst(inst_data.operand); + var base_ptr = start_ptr; + while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) { + .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false), + .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false), + else => break, + }; + + const elem_ty = sema.typeOf(base_ptr).childType(); + switch (elem_ty.zigTypeTag()) { + .Array, .Vector => return base_ptr, + .Struct => if (elem_ty.isTuple()) return base_ptr, + else => {}, + } + return sema.fail(block, src, "type '{}' does not support array initialization syntax", .{ + sema.typeOf(start_ptr).childType(), + }); +} + +fn zirFieldBasePtr( + sema: *Sema, + block: *Block, + inst: Zir.Inst.Index, +) CompileError!Air.Inst.Ref { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + + const start_ptr = sema.resolveInst(inst_data.operand); + var base_ptr = start_ptr; + while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) { + .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false), + .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false), + else => break, + }; + + const elem_ty = sema.typeOf(base_ptr).childType(); + switch (elem_ty.zigTypeTag()) { + .Struct, .Union => return base_ptr, + else => {}, + } + return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{ + sema.typeOf(start_ptr).childType(), + }); +} + fn zirValidateStructInit( sema: *Sema, block: *Block, @@ -4377,7 +4432,9 @@ fn analyzeCall( if (payload.data.error_set.tag() == .error_set_inferred) { const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode); node.data = .{ .func = module_fn }; - parent_func.?.inferred_error_sets.prepend(node); + if (parent_func) |some| { + some.inferred_error_sets.prepend(node); + } const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data); break :blk try Type.Tag.error_union.create(sema.arena, .{ @@ -5198,9 +5255,20 @@ fn zirOptionalPayloadPtr( const inst_data = sema.code.instructions.items(.data)[inst].un_node; const optional_ptr = sema.resolveInst(inst_data.operand); + const src = inst_data.src(); + + return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check); +} + +fn analyzeOptionalPayloadPtr( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + optional_ptr: Air.Inst.Ref, + safety_check: bool, +) CompileError!Air.Inst.Ref { const optional_ptr_ty = sema.typeOf(optional_ptr); assert(optional_ptr_ty.zigTypeTag() == .Pointer); - const src = inst_data.src(); const opt_type = optional_ptr_ty.elemType(); if (opt_type.zigTypeTag() != .Optional) { @@ -5216,8 +5284,10 @@ fn zirOptionalPayloadPtr( if (try sema.resolveDefinedValue(block, src, optional_ptr)) |pointer_val| { if (try sema.pointerDeref(block, src, pointer_val, optional_ptr_ty)) |val| { - if (val.isNull()) { - return sema.fail(block, src, "unable to unwrap null", .{}); + if (safety_check) { + if (val.isNull()) { + return sema.fail(block, src, "unable to unwrap null", .{}); + } } // The same Value represents the pointer to the optional and the payload. return sema.addConstant( @@ -5333,8 +5403,19 @@ fn zirErrUnionPayloadPtr( defer tracy.end(); const inst_data = sema.code.instructions.items(.data)[inst].un_node; - const src = inst_data.src(); const operand = sema.resolveInst(inst_data.operand); + const src = inst_data.src(); + + return sema.analyzeErrUnionPayloadPtr(block, src, operand, safety_check); +} + +fn analyzeErrUnionPayloadPtr( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + operand: Air.Inst.Ref, + safety_check: bool, +) CompileError!Air.Inst.Ref { const operand_ty = sema.typeOf(operand); assert(operand_ty.zigTypeTag() == .Pointer); @@ -5350,9 +5431,12 @@ fn zirErrUnionPayloadPtr( if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| { if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| { - if (val.getError()) |name| { - return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); + if (safety_check) { + if (val.getError()) |name| { + return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); + } } + return sema.addConstant( operand_pointer_ty, try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val), @@ -12859,7 +12943,7 @@ fn zirCUndef( extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; - const src: LazySrcLoc = .{ .node_offset = extra.node }; + const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; const name = try sema.resolveConstString(block, src, extra.operand); try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name}); @@ -12872,7 +12956,7 @@ fn zirCInclude( extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; - const src: LazySrcLoc = .{ .node_offset = extra.node }; + const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; const name = try sema.resolveConstString(block, src, extra.operand); try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name}); @@ -12885,12 +12969,13 @@ fn zirCDefine( extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; - const src: LazySrcLoc = .{ .node_offset = extra.node }; + const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; + const val_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; - const name = try sema.resolveConstString(block, src, extra.lhs); + const name = try sema.resolveConstString(block, name_src, extra.lhs); const rhs = sema.resolveInst(extra.rhs); if (sema.typeOf(rhs).zigTypeTag() != .Void) { - const value = try sema.resolveConstString(block, src, extra.rhs); + const value = try sema.resolveConstString(block, val_src, extra.rhs); try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value }); } else { try block.c_import_buf.?.writer().print("#define {s}\n", .{name}); diff --git a/src/Zir.zig b/src/Zir.zig index b8ff7ae50f..339a141c15 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -643,6 +643,18 @@ pub const Inst = struct { /// Result is a pointer to the value. /// Uses the `switch_capture` field. switch_capture_multi_ref, + /// Given a + /// *A returns *A + /// *E!A returns *A + /// *?A returns *A + /// Uses the `un_node` field. + array_base_ptr, + /// Given a + /// *S returns *S + /// *E!S returns *S + /// *?S returns *S + /// Uses the `un_node` field. + field_base_ptr, /// Given a set of `field_ptr` instructions, assumes they are all part of a struct /// initialization expression, and emits compile errors for duplicate fields /// as well as missing fields, if applicable. @@ -1087,6 +1099,8 @@ pub const Inst = struct { .switch_block, .switch_cond, .switch_cond_ref, + .array_base_ptr, + .field_base_ptr, .validate_struct_init, .validate_struct_init_comptime, .validate_array_init, @@ -1340,6 +1354,8 @@ pub const Inst = struct { .switch_capture_ref = .switch_capture, .switch_capture_multi = .switch_capture, .switch_capture_multi_ref = .switch_capture, + .array_base_ptr = .un_node, + .field_base_ptr = .un_node, .validate_struct_init = .pl_node, .validate_struct_init_comptime = .pl_node, .validate_array_init = .pl_node, diff --git a/src/print_zir.zig b/src/print_zir.zig index 6396f11467..5349d515aa 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -235,6 +235,8 @@ const Writer = struct { .fence, .switch_cond, .switch_cond_ref, + .array_base_ptr, + .field_base_ptr, => try self.writeUnNode(stream, inst), .ref, |
