diff options
| -rw-r--r-- | src/Air.zig | 3 | ||||
| -rw-r--r-- | src/Module.zig | 4 | ||||
| -rw-r--r-- | src/Sema.zig | 85 | ||||
| -rw-r--r-- | src/type.zig | 3 |
4 files changed, 73 insertions, 22 deletions
diff --git a/src/Air.zig b/src/Air.zig index 6888f51963..a044dd6294 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -521,7 +521,8 @@ pub const Inst = struct { /// Some of the elements may be comptime-known. /// Uses the `ty_pl` field, payload is index of an array of elements, each of which /// is a `Ref`. Length of the array is given by the vector type. - /// TODO rename this to `array_init` and make it support array values too. + /// TODO rename this to `aggregate_init` and make it support array values and + /// struct values too. vector_init, /// Communicates an intent to load memory. diff --git a/src/Module.zig b/src/Module.zig index bc806cfb9c..3631e41f25 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3547,7 +3547,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { .code = file.zir, .owner_decl = new_decl, .func = null, - .fn_ret_ty = Type.initTag(.void), + .fn_ret_ty = Type.void, .owner_func = null, }; defer sema.deinit(); @@ -3628,7 +3628,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { .code = zir, .owner_decl = decl, .func = null, - .fn_ret_ty = Type.initTag(.void), + .fn_ret_ty = Type.void, .owner_func = null, }; defer sema.deinit(); diff --git a/src/Sema.zig b/src/Sema.zig index df5013fbaf..38adfb4798 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3187,12 +3187,32 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v const tracy = trace(@src()); defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const zir_tags = sema.code.instructions.items(.tag); + const zir_datas = sema.code.instructions.items(.data); + const inst_data = zir_datas[inst].pl_node; const src = inst_data.src(); const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const ptr = sema.resolveInst(extra.lhs); - const value = sema.resolveInst(extra.rhs); - return sema.storePtr(block, src, ptr, value); + const operand = sema.resolveInst(extra.rhs); + + // Check for the possibility of this pattern: + // %a = ret_ptr + // %b = store(%a, %c) + // Where %c is an error union. In such case we need to add to the current function's + // inferred error set, if any. + if (sema.typeOf(operand).zigTypeTag() == .ErrorUnion and + sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) + { + if (Zir.refToIndex(extra.lhs)) |ptr_index| { + if (zir_tags[ptr_index] == .extended and + zir_datas[ptr_index].extended.opcode == .ret_ptr) + { + try sema.addToInferredErrorSet(operand); + } + } + } + + return sema.storePtr(block, src, ptr, operand); } fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -10400,6 +10420,23 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir return always_noreturn; } +fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { + assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion); + + if (sema.fn_ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| { + const op_ty = sema.typeOf(uncasted_operand); + switch (op_ty.zigTypeTag()) { + .ErrorSet => { + try payload.data.addErrorSet(sema.gpa, op_ty); + }, + .ErrorUnion => { + try payload.data.addErrorSet(sema.gpa, op_ty.errorUnionSet()); + }, + else => {}, + } + } +} + fn analyzeRet( sema: *Sema, block: *Block, @@ -10410,18 +10447,7 @@ fn analyzeRet( // add the error tag to the inferred error set of the in-scope function, so // that the coercion below works correctly. if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) { - if (sema.fn_ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| { - const op_ty = sema.typeOf(uncasted_operand); - switch (op_ty.zigTypeTag()) { - .ErrorSet => { - try payload.data.addErrorSet(sema.gpa, op_ty); - }, - .ErrorUnion => { - try payload.data.addErrorSet(sema.gpa, op_ty.errorUnionSet()); - }, - else => {}, - } - } + try sema.addToInferredErrorSet(uncasted_operand); } const operand = try sema.coerce(block, sema.fn_ret_ty, uncasted_operand, src); @@ -14355,9 +14381,32 @@ fn coerce( }, else => {}, }, - .ErrorUnion => { - // T to E!T or E to E!T - return sema.wrapErrorUnion(block, dest_ty, inst, inst_src); + .ErrorUnion => switch (inst_ty.zigTypeTag()) { + .ErrorUnion => { + if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |inst_val| { + switch (inst_val.tag()) { + .undef => return sema.addConstUndef(dest_ty), + .eu_payload => { + const payload = try sema.addConstant( + inst_ty.errorUnionPayload(), + inst_val.castTag(.eu_payload).?.data, + ); + return sema.wrapErrorUnion(block, dest_ty, payload, inst_src); + }, + else => { + const error_set = try sema.addConstant( + inst_ty.errorUnionSet(), + inst_val, + ); + return sema.wrapErrorUnion(block, dest_ty, error_set, inst_src); + }, + } + } + }, + else => { + // T to E!T or E to E!T + return sema.wrapErrorUnion(block, dest_ty, inst, inst_src); + }, }, .Union => switch (inst_ty.zigTypeTag()) { .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src), diff --git a/src/type.zig b/src/type.zig index 769e48ccc5..0827b2e2d7 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3013,7 +3013,7 @@ pub const Type = extern union { } } - /// Asserts the type is an array or vector. + /// Asserts the type is an array or vector or struct. pub fn arrayLen(ty: Type) u64 { return switch (ty.tag()) { .vector => ty.castTag(.vector).?.data.len, @@ -3022,6 +3022,7 @@ pub const Type = extern union { .array_u8 => ty.castTag(.array_u8).?.data, .array_u8_sentinel_0 => ty.castTag(.array_u8_sentinel_0).?.data, .tuple => ty.castTag(.tuple).?.data.types.len, + .@"struct" => ty.castTag(.@"struct").?.data.fields.count(), else => unreachable, }; |
