| author | |
| committer | |
| log | 74303a3d9591f188fb4dda96bf689c00ebbd24ca |
| tree | 936ea6f3afe985b9cc3110eca1d4b1750a4fca2f |
| parent | 628e9e6d040979bd0a2cba05e854014dee5a7d55 |
| parent | a5ac06268972bd7279a1bb928a40d70cc7d515ed |
| signature |
stage2: support anon init through error unions and optionals16 files changed, 374 insertions(+), 32 deletions(-)
src/Air.zig+4| ... | ... | @@ -429,6 +429,9 @@ pub const Inst = struct { |
| 429 | 429 | /// *(E!T) -> E. If the value is not an error, undefined behavior. |
| 430 | 430 | /// Uses the `ty_op` field. |
| 431 | 431 | unwrap_errunion_err_ptr, |
| 432 | /// *(E!T) => *T. Sets the value to non-error with an undefined payload value. | |
| 433 | /// Uses the `ty_op` field. | |
| 434 | errunion_payload_ptr_set, | |
| 432 | 435 | /// wrap from T to E!T |
| 433 | 436 | /// Uses the `ty_op` field. |
| 434 | 437 | wrap_errunion_payload, |
| ... | ... | @@ -865,6 +868,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 865 | 868 | .optional_payload, |
| 866 | 869 | .optional_payload_ptr, |
| 867 | 870 | .optional_payload_ptr_set, |
| 871 | .errunion_payload_ptr_set, | |
| 868 | 872 | .wrap_optional, |
| 869 | 873 | .unwrap_errunion_payload, |
| 870 | 874 | .unwrap_errunion_err, |
src/AstGen.zig+18-4| ... | ... | @@ -1297,6 +1297,7 @@ fn arrayInitExpr( |
| 1297 | 1297 | } |
| 1298 | 1298 | } |
| 1299 | 1299 | const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr); |
| 1300 | _ = try gz.addUnNode(.validate_array_init_ty, array_type_inst, node); | |
| 1300 | 1301 | const elem_type = try gz.addUnNode(.elem_type, array_type_inst, array_init.ast.type_expr); |
| 1301 | 1302 | break :inst .{ |
| 1302 | 1303 | .array = array_type_inst, |
| ... | ... | @@ -1399,7 +1400,8 @@ fn arrayInitExprRlPtr( |
| 1399 | 1400 | array_ty: Zir.Inst.Ref, |
| 1400 | 1401 | ) InnerError!Zir.Inst.Ref { |
| 1401 | 1402 | if (array_ty == .none) { |
| 1402 | return arrayInitExprRlPtrInner(gz, scope, node, result_ptr, elements); | |
| 1403 | const base_ptr = try gz.addUnNode(.array_base_ptr, result_ptr, node); | |
| 1404 | return arrayInitExprRlPtrInner(gz, scope, node, base_ptr, elements); | |
| 1403 | 1405 | } |
| 1404 | 1406 | |
| 1405 | 1407 | var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr); |
| ... | ... | @@ -1508,8 +1510,11 @@ fn structInitExpr( |
| 1508 | 1510 | |
| 1509 | 1511 | switch (rl) { |
| 1510 | 1512 | .discard => { |
| 1511 | if (struct_init.ast.type_expr != 0) | |
| 1512 | _ = try typeExpr(gz, scope, struct_init.ast.type_expr); | |
| 1513 | // TODO if a type expr is given the fields should be validated for that type | |
| 1514 | if (struct_init.ast.type_expr != 0) { | |
| 1515 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); | |
| 1516 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); | |
| 1517 | } | |
| 1513 | 1518 | for (struct_init.ast.fields) |field_init| { |
| 1514 | 1519 | _ = try expr(gz, scope, .discard, field_init); |
| 1515 | 1520 | } |
| ... | ... | @@ -1518,6 +1523,7 @@ fn structInitExpr( |
| 1518 | 1523 | .ref => { |
| 1519 | 1524 | if (struct_init.ast.type_expr != 0) { |
| 1520 | 1525 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1526 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); | |
| 1521 | 1527 | return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref); |
| 1522 | 1528 | } else { |
| 1523 | 1529 | return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref); |
| ... | ... | @@ -1526,6 +1532,7 @@ fn structInitExpr( |
| 1526 | 1532 | .none => { |
| 1527 | 1533 | if (struct_init.ast.type_expr != 0) { |
| 1528 | 1534 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1535 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); | |
| 1529 | 1536 | return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); |
| 1530 | 1537 | } else { |
| 1531 | 1538 | return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon); |
| ... | ... | @@ -1536,6 +1543,7 @@ fn structInitExpr( |
| 1536 | 1543 | return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); |
| 1537 | 1544 | } |
| 1538 | 1545 | const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1546 | _ = try gz.addUnNode(.validate_struct_init_ty, inner_ty_inst, node); | |
| 1539 | 1547 | const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init); |
| 1540 | 1548 | return rvalue(gz, rl, result, node); |
| 1541 | 1549 | }, |
| ... | ... | @@ -1582,9 +1590,11 @@ fn structInitExprRlPtr( |
| 1582 | 1590 | result_ptr: Zir.Inst.Ref, |
| 1583 | 1591 | ) InnerError!Zir.Inst.Ref { |
| 1584 | 1592 | if (struct_init.ast.type_expr == 0) { |
| 1585 | return structInitExprRlPtrInner(gz, scope, node, struct_init, result_ptr); | |
| 1593 | const base_ptr = try gz.addUnNode(.field_base_ptr, result_ptr, node); | |
| 1594 | return structInitExprRlPtrInner(gz, scope, node, struct_init, base_ptr); | |
| 1586 | 1595 | } |
| 1587 | 1596 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1597 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); | |
| 1588 | 1598 | |
| 1589 | 1599 | var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr); |
| 1590 | 1600 | defer as_scope.unstack(); |
| ... | ... | @@ -2298,6 +2308,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2298 | 2308 | .ret_err_value_code, |
| 2299 | 2309 | .extended, |
| 2300 | 2310 | .closure_get, |
| 2311 | .array_base_ptr, | |
| 2312 | .field_base_ptr, | |
| 2301 | 2313 | => break :b false, |
| 2302 | 2314 | |
| 2303 | 2315 | // ZIR instructions that are always `noreturn`. |
| ... | ... | @@ -2346,6 +2358,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2346 | 2358 | .closure_capture, |
| 2347 | 2359 | .memcpy, |
| 2348 | 2360 | .memset, |
| 2361 | .validate_array_init_ty, | |
| 2362 | .validate_struct_init_ty, | |
| 2349 | 2363 | => break :b true, |
| 2350 | 2364 | } |
| 2351 | 2365 | } else switch (maybe_unused_result) { |
src/Liveness.zig+1| ... | ... | @@ -293,6 +293,7 @@ fn analyzeInst( |
| 293 | 293 | .optional_payload, |
| 294 | 294 | .optional_payload_ptr, |
| 295 | 295 | .optional_payload_ptr_set, |
| 296 | .errunion_payload_ptr_set, | |
| 296 | 297 | .wrap_optional, |
| 297 | 298 | .unwrap_errunion_payload, |
| 298 | 299 | .unwrap_errunion_err, |
src/Sema.zig+166-12| ... | ... | @@ -739,6 +739,8 @@ fn analyzeBodyInner( |
| 739 | 739 | .@"await" => try sema.zirAwait(block, inst, false), |
| 740 | 740 | .await_nosuspend => try sema.zirAwait(block, inst, true), |
| 741 | 741 | .extended => try sema.zirExtended(block, inst), |
| 742 | .array_base_ptr => try sema.zirArrayBasePtr(block, inst), | |
| 743 | .field_base_ptr => try sema.zirFieldBasePtr(block, inst), | |
| 742 | 744 | |
| 743 | 745 | .clz => try sema.zirBitCount(block, inst, .clz, Value.clz), |
| 744 | 746 | .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz), |
| ... | ... | @@ -870,6 +872,16 @@ fn analyzeBodyInner( |
| 870 | 872 | i += 1; |
| 871 | 873 | continue; |
| 872 | 874 | }, |
| 875 | .validate_array_init_ty => { | |
| 876 | try sema.validateArrayInitTy(block, inst); | |
| 877 | i += 1; | |
| 878 | continue; | |
| 879 | }, | |
| 880 | .validate_struct_init_ty => { | |
| 881 | try sema.validateStructInitTy(block, inst); | |
| 882 | i += 1; | |
| 883 | continue; | |
| 884 | }, | |
| 873 | 885 | .validate_struct_init => { |
| 874 | 886 | try sema.zirValidateStructInit(block, inst, false); |
| 875 | 887 | i += 1; |
| ... | ... | @@ -1346,6 +1358,14 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, opt |
| 1346 | 1358 | return sema.fail(block, src, "expected optional type, found {}", .{optional_ty}); |
| 1347 | 1359 | } |
| 1348 | 1360 | |
| 1361 | fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { | |
| 1362 | return sema.fail(block, src, "type '{}' does not support array initialization syntax", .{ty}); | |
| 1363 | } | |
| 1364 | ||
| 1365 | fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { | |
| 1366 | return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{ty}); | |
| 1367 | } | |
| 1368 | ||
| 1349 | 1369 | fn failWithErrorSetCodeMissing( |
| 1350 | 1370 | sema: *Sema, |
| 1351 | 1371 | block: *Block, |
| ... | ... | @@ -1641,7 +1661,13 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1641 | 1661 | return sema.fail(block, src, "TODO coerce_result_ptr wrap_errunion_err", .{}); |
| 1642 | 1662 | }, |
| 1643 | 1663 | .wrap_errunion_payload => { |
| 1644 | return sema.fail(block, src, "TODO coerce_result_ptr wrap_errunion_payload", .{}); | |
| 1664 | const ty_op = air_datas[trash_inst].ty_op; | |
| 1665 | const payload_ty = sema.getTmpAir().typeOf(ty_op.operand); | |
| 1666 | const ptr_payload_ty = try Type.ptr(sema.arena, .{ | |
| 1667 | .pointee_type = payload_ty, | |
| 1668 | .@"addrspace" = addr_space, | |
| 1669 | }); | |
| 1670 | new_ptr = try block.addTyOp(.errunion_payload_ptr_set, ptr_payload_ty, new_ptr); | |
| 1645 | 1671 | }, |
| 1646 | 1672 | else => { |
| 1647 | 1673 | if (std.debug.runtime_safety) { |
| ... | ... | @@ -2591,6 +2617,88 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 2591 | 2617 | } |
| 2592 | 2618 | } |
| 2593 | 2619 | |
| 2620 | fn zirArrayBasePtr( | |
| 2621 | sema: *Sema, | |
| 2622 | block: *Block, | |
| 2623 | inst: Zir.Inst.Index, | |
| 2624 | ) CompileError!Air.Inst.Ref { | |
| 2625 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | |
| 2626 | const src = inst_data.src(); | |
| 2627 | ||
| 2628 | const start_ptr = sema.resolveInst(inst_data.operand); | |
| 2629 | var base_ptr = start_ptr; | |
| 2630 | while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) { | |
| 2631 | .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), | |
| 2632 | .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), | |
| 2633 | else => break, | |
| 2634 | }; | |
| 2635 | ||
| 2636 | const elem_ty = sema.typeOf(base_ptr).childType(); | |
| 2637 | switch (elem_ty.zigTypeTag()) { | |
| 2638 | .Array, .Vector => return base_ptr, | |
| 2639 | .Struct => if (elem_ty.isTuple()) return base_ptr, | |
| 2640 | else => {}, | |
| 2641 | } | |
| 2642 | return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType()); | |
| 2643 | } | |
| 2644 | ||
| 2645 | fn zirFieldBasePtr( | |
| 2646 | sema: *Sema, | |
| 2647 | block: *Block, | |
| 2648 | inst: Zir.Inst.Index, | |
| 2649 | ) CompileError!Air.Inst.Ref { | |
| 2650 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | |
| 2651 | const src = inst_data.src(); | |
| 2652 | ||
| 2653 | const start_ptr = sema.resolveInst(inst_data.operand); | |
| 2654 | var base_ptr = start_ptr; | |
| 2655 | while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) { | |
| 2656 | .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), | |
| 2657 | .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), | |
| 2658 | else => break, | |
| 2659 | }; | |
| 2660 | ||
| 2661 | const elem_ty = sema.typeOf(base_ptr).childType(); | |
| 2662 | switch (elem_ty.zigTypeTag()) { | |
| 2663 | .Struct, .Union => return base_ptr, | |
| 2664 | else => {}, | |
| 2665 | } | |
| 2666 | return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType()); | |
| 2667 | } | |
| 2668 | ||
| 2669 | fn validateArrayInitTy( | |
| 2670 | sema: *Sema, | |
| 2671 | block: *Block, | |
| 2672 | inst: Zir.Inst.Index, | |
| 2673 | ) CompileError!void { | |
| 2674 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | |
| 2675 | const src = inst_data.src(); | |
| 2676 | const ty = try sema.resolveType(block, src, inst_data.operand); | |
| 2677 | ||
| 2678 | switch (ty.zigTypeTag()) { | |
| 2679 | .Array, .Vector => return, | |
| 2680 | .Struct => if (ty.isTuple()) return, | |
| 2681 | else => {}, | |
| 2682 | } | |
| 2683 | return sema.failWithArrayInitNotSupported(block, src, ty); | |
| 2684 | } | |
| 2685 | ||
| 2686 | fn validateStructInitTy( | |
| 2687 | sema: *Sema, | |
| 2688 | block: *Block, | |
| 2689 | inst: Zir.Inst.Index, | |
| 2690 | ) CompileError!void { | |
| 2691 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | |
| 2692 | const src = inst_data.src(); | |
| 2693 | const ty = try sema.resolveType(block, src, inst_data.operand); | |
| 2694 | ||
| 2695 | switch (ty.zigTypeTag()) { | |
| 2696 | .Struct, .Union => return, | |
| 2697 | else => {}, | |
| 2698 | } | |
| 2699 | return sema.failWithStructInitNotSupported(block, src, ty); | |
| 2700 | } | |
| 2701 | ||
| 2594 | 2702 | fn zirValidateStructInit( |
| 2595 | 2703 | sema: *Sema, |
| 2596 | 2704 | block: *Block, |
| ... | ... | @@ -4396,7 +4504,9 @@ fn analyzeCall( |
| 4396 | 4504 | if (payload.data.error_set.tag() == .error_set_inferred) { |
| 4397 | 4505 | const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode); |
| 4398 | 4506 | node.data = .{ .func = module_fn }; |
| 4399 | parent_func.?.inferred_error_sets.prepend(node); | |
| 4507 | if (parent_func) |some| { | |
| 4508 | some.inferred_error_sets.prepend(node); | |
| 4509 | } | |
| 4400 | 4510 | |
| 4401 | 4511 | const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data); |
| 4402 | 4512 | break :blk try Type.Tag.error_union.create(sema.arena, .{ |
| ... | ... | @@ -5217,9 +5327,21 @@ fn zirOptionalPayloadPtr( |
| 5217 | 5327 | |
| 5218 | 5328 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 5219 | 5329 | const optional_ptr = sema.resolveInst(inst_data.operand); |
| 5330 | const src = inst_data.src(); | |
| 5331 | ||
| 5332 | return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false); | |
| 5333 | } | |
| 5334 | ||
| 5335 | fn analyzeOptionalPayloadPtr( | |
| 5336 | sema: *Sema, | |
| 5337 | block: *Block, | |
| 5338 | src: LazySrcLoc, | |
| 5339 | optional_ptr: Air.Inst.Ref, | |
| 5340 | safety_check: bool, | |
| 5341 | initializing: bool, | |
| 5342 | ) CompileError!Air.Inst.Ref { | |
| 5220 | 5343 | const optional_ptr_ty = sema.typeOf(optional_ptr); |
| 5221 | 5344 | assert(optional_ptr_ty.zigTypeTag() == .Pointer); |
| 5222 | const src = inst_data.src(); | |
| 5223 | 5345 | |
| 5224 | 5346 | const opt_type = optional_ptr_ty.elemType(); |
| 5225 | 5347 | if (opt_type.zigTypeTag() != .Optional) { |
| ... | ... | @@ -5234,6 +5356,12 @@ fn zirOptionalPayloadPtr( |
| 5234 | 5356 | }); |
| 5235 | 5357 | |
| 5236 | 5358 | if (try sema.resolveDefinedValue(block, src, optional_ptr)) |pointer_val| { |
| 5359 | if (initializing) { | |
| 5360 | return sema.addConstant( | |
| 5361 | child_pointer, | |
| 5362 | try Value.Tag.opt_payload_ptr.create(sema.arena, pointer_val), | |
| 5363 | ); | |
| 5364 | } | |
| 5237 | 5365 | if (try sema.pointerDeref(block, src, pointer_val, optional_ptr_ty)) |val| { |
| 5238 | 5366 | if (val.isNull()) { |
| 5239 | 5367 | return sema.fail(block, src, "unable to unwrap null", .{}); |
| ... | ... | @@ -5251,7 +5379,10 @@ fn zirOptionalPayloadPtr( |
| 5251 | 5379 | const is_non_null = try block.addUnOp(.is_non_null_ptr, optional_ptr); |
| 5252 | 5380 | try sema.addSafetyCheck(block, is_non_null, .unwrap_null); |
| 5253 | 5381 | } |
| 5254 | return block.addTyOp(.optional_payload_ptr, child_pointer, optional_ptr); | |
| 5382 | return block.addTyOp(if (initializing) | |
| 5383 | .optional_payload_ptr_set | |
| 5384 | else | |
| 5385 | .optional_payload_ptr, child_pointer, optional_ptr); | |
| 5255 | 5386 | } |
| 5256 | 5387 | |
| 5257 | 5388 | /// Value in, value out. |
| ... | ... | @@ -5352,8 +5483,20 @@ fn zirErrUnionPayloadPtr( |
| 5352 | 5483 | defer tracy.end(); |
| 5353 | 5484 | |
| 5354 | 5485 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 5355 | const src = inst_data.src(); | |
| 5356 | 5486 | const operand = sema.resolveInst(inst_data.operand); |
| 5487 | const src = inst_data.src(); | |
| 5488 | ||
| 5489 | return sema.analyzeErrUnionPayloadPtr(block, src, operand, safety_check, false); | |
| 5490 | } | |
| 5491 | ||
| 5492 | fn analyzeErrUnionPayloadPtr( | |
| 5493 | sema: *Sema, | |
| 5494 | block: *Block, | |
| 5495 | src: LazySrcLoc, | |
| 5496 | operand: Air.Inst.Ref, | |
| 5497 | safety_check: bool, | |
| 5498 | initializing: bool, | |
| 5499 | ) CompileError!Air.Inst.Ref { | |
| 5357 | 5500 | const operand_ty = sema.typeOf(operand); |
| 5358 | 5501 | assert(operand_ty.zigTypeTag() == .Pointer); |
| 5359 | 5502 | |
| ... | ... | @@ -5368,10 +5511,17 @@ fn zirErrUnionPayloadPtr( |
| 5368 | 5511 | }); |
| 5369 | 5512 | |
| 5370 | 5513 | if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| { |
| 5514 | if (initializing) { | |
| 5515 | return sema.addConstant( | |
| 5516 | operand_pointer_ty, | |
| 5517 | try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val), | |
| 5518 | ); | |
| 5519 | } | |
| 5371 | 5520 | if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| { |
| 5372 | 5521 | if (val.getError()) |name| { |
| 5373 | 5522 | return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); |
| 5374 | 5523 | } |
| 5524 | ||
| 5375 | 5525 | return sema.addConstant( |
| 5376 | 5526 | operand_pointer_ty, |
| 5377 | 5527 | try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val), |
| ... | ... | @@ -5384,7 +5534,10 @@ fn zirErrUnionPayloadPtr( |
| 5384 | 5534 | const is_non_err = try block.addUnOp(.is_err, operand); |
| 5385 | 5535 | try sema.addSafetyCheck(block, is_non_err, .unwrap_errunion); |
| 5386 | 5536 | } |
| 5387 | return block.addTyOp(.unwrap_errunion_payload_ptr, operand_pointer_ty, operand); | |
| 5537 | return block.addTyOp(if (initializing) | |
| 5538 | .errunion_payload_ptr_set | |
| 5539 | else | |
| 5540 | .unwrap_errunion_payload_ptr, operand_pointer_ty, operand); | |
| 5388 | 5541 | } |
| 5389 | 5542 | |
| 5390 | 5543 | /// Value in, value out |
| ... | ... | @@ -10778,7 +10931,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 10778 | 10931 | .Struct => return structInitEmpty(sema, block, obj_ty, src, src), |
| 10779 | 10932 | .Array => return arrayInitEmpty(sema, obj_ty), |
| 10780 | 10933 | .Void => return sema.addConstant(obj_ty, Value.void), |
| 10781 | else => unreachable, | |
| 10934 | else => return sema.failWithArrayInitNotSupported(block, src, obj_ty), | |
| 10782 | 10935 | } |
| 10783 | 10936 | } |
| 10784 | 10937 | |
| ... | ... | @@ -12920,7 +13073,7 @@ fn zirCUndef( |
| 12920 | 13073 | extended: Zir.Inst.Extended.InstData, |
| 12921 | 13074 | ) CompileError!Air.Inst.Ref { |
| 12922 | 13075 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 12923 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | |
| 13076 | const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | |
| 12924 | 13077 | |
| 12925 | 13078 | const name = try sema.resolveConstString(block, src, extra.operand); |
| 12926 | 13079 | try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name}); |
| ... | ... | @@ -12933,7 +13086,7 @@ fn zirCInclude( |
| 12933 | 13086 | extended: Zir.Inst.Extended.InstData, |
| 12934 | 13087 | ) CompileError!Air.Inst.Ref { |
| 12935 | 13088 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 12936 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | |
| 13089 | const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | |
| 12937 | 13090 | |
| 12938 | 13091 | const name = try sema.resolveConstString(block, src, extra.operand); |
| 12939 | 13092 | try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name}); |
| ... | ... | @@ -12946,12 +13099,13 @@ fn zirCDefine( |
| 12946 | 13099 | extended: Zir.Inst.Extended.InstData, |
| 12947 | 13100 | ) CompileError!Air.Inst.Ref { |
| 12948 | 13101 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 12949 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | |
| 13102 | const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | |
| 13103 | const val_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; | |
| 12950 | 13104 | |
| 12951 | const name = try sema.resolveConstString(block, src, extra.lhs); | |
| 13105 | const name = try sema.resolveConstString(block, name_src, extra.lhs); | |
| 12952 | 13106 | const rhs = sema.resolveInst(extra.rhs); |
| 12953 | 13107 | if (sema.typeOf(rhs).zigTypeTag() != .Void) { |
| 12954 | const value = try sema.resolveConstString(block, src, extra.rhs); | |
| 13108 | const value = try sema.resolveConstString(block, val_src, extra.rhs); | |
| 12955 | 13109 | try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value }); |
| 12956 | 13110 | } else { |
| 12957 | 13111 | try block.c_import_buf.?.writer().print("#define {s}\n", .{name}); |
src/Zir.zig+26| ... | ... | @@ -643,6 +643,24 @@ pub const Inst = struct { |
| 643 | 643 | /// Result is a pointer to the value. |
| 644 | 644 | /// Uses the `switch_capture` field. |
| 645 | 645 | switch_capture_multi_ref, |
| 646 | /// Given a | |
| 647 | /// *A returns *A | |
| 648 | /// *E!A returns *A | |
| 649 | /// *?A returns *A | |
| 650 | /// Uses the `un_node` field. | |
| 651 | array_base_ptr, | |
| 652 | /// Given a | |
| 653 | /// *S returns *S | |
| 654 | /// *E!S returns *S | |
| 655 | /// *?S returns *S | |
| 656 | /// Uses the `un_node` field. | |
| 657 | field_base_ptr, | |
| 658 | /// Checks that the type supports array init syntax. | |
| 659 | /// Uses the `un_node` field. | |
| 660 | validate_array_init_ty, | |
| 661 | /// Checks that the type supports struct init syntax. | |
| 662 | /// Uses the `un_node` field. | |
| 663 | validate_struct_init_ty, | |
| 646 | 664 | /// Given a set of `field_ptr` instructions, assumes they are all part of a struct |
| 647 | 665 | /// initialization expression, and emits compile errors for duplicate fields |
| 648 | 666 | /// as well as missing fields, if applicable. |
| ... | ... | @@ -1087,6 +1105,10 @@ pub const Inst = struct { |
| 1087 | 1105 | .switch_block, |
| 1088 | 1106 | .switch_cond, |
| 1089 | 1107 | .switch_cond_ref, |
| 1108 | .array_base_ptr, | |
| 1109 | .field_base_ptr, | |
| 1110 | .validate_array_init_ty, | |
| 1111 | .validate_struct_init_ty, | |
| 1090 | 1112 | .validate_struct_init, |
| 1091 | 1113 | .validate_struct_init_comptime, |
| 1092 | 1114 | .validate_array_init, |
| ... | ... | @@ -1340,6 +1362,10 @@ pub const Inst = struct { |
| 1340 | 1362 | .switch_capture_ref = .switch_capture, |
| 1341 | 1363 | .switch_capture_multi = .switch_capture, |
| 1342 | 1364 | .switch_capture_multi_ref = .switch_capture, |
| 1365 | .array_base_ptr = .un_node, | |
| 1366 | .field_base_ptr = .un_node, | |
| 1367 | .validate_array_init_ty = .un_node, | |
| 1368 | .validate_struct_init_ty = .un_node, | |
| 1343 | 1369 | .validate_struct_init = .pl_node, |
| 1344 | 1370 | .validate_struct_init_comptime = .pl_node, |
| 1345 | 1371 | .validate_array_init = .pl_node, |
src/arch/aarch64/CodeGen.zig+7| ... | ... | @@ -662,6 +662,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 662 | 662 | .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst), |
| 663 | 663 | .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), |
| 664 | 664 | .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), |
| 665 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), | |
| 665 | 666 | |
| 666 | 667 | .wrap_optional => try self.airWrapOptional(inst), |
| 667 | 668 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | ... | @@ -1443,6 +1444,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1443 | 1444 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1444 | 1445 | } |
| 1445 | 1446 | |
| 1447 | fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | |
| 1448 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | |
| 1449 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch}); | |
| 1450 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | |
| 1451 | } | |
| 1452 | ||
| 1446 | 1453 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1447 | 1454 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1448 | 1455 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
src/arch/arm/CodeGen.zig+7| ... | ... | @@ -646,6 +646,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 646 | 646 | .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst), |
| 647 | 647 | .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), |
| 648 | 648 | .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), |
| 649 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), | |
| 649 | 650 | |
| 650 | 651 | .wrap_optional => try self.airWrapOptional(inst), |
| 651 | 652 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | ... | @@ -1154,6 +1155,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1154 | 1155 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1155 | 1156 | } |
| 1156 | 1157 | |
| 1158 | fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | |
| 1159 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | |
| 1160 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch}); | |
| 1161 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | |
| 1162 | } | |
| 1163 | ||
| 1157 | 1164 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1158 | 1165 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1159 | 1166 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
src/arch/riscv64/CodeGen.zig+7| ... | ... | @@ -633,6 +633,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 633 | 633 | .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst), |
| 634 | 634 | .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), |
| 635 | 635 | .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), |
| 636 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), | |
| 636 | 637 | |
| 637 | 638 | .wrap_optional => try self.airWrapOptional(inst), |
| 638 | 639 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | ... | @@ -1065,6 +1066,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1065 | 1066 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1066 | 1067 | } |
| 1067 | 1068 | |
| 1069 | fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | |
| 1070 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | |
| 1071 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch}); | |
| 1072 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | |
| 1073 | } | |
| 1074 | ||
| 1068 | 1075 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1069 | 1076 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1070 | 1077 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
src/arch/wasm/CodeGen.zig+1| ... | ... | @@ -1725,6 +1725,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1725 | 1725 | .atomic_rmw, |
| 1726 | 1726 | .tag_name, |
| 1727 | 1727 | .error_name, |
| 1728 | .errunion_payload_ptr_set, | |
| 1728 | 1729 | |
| 1729 | 1730 | // For these 4, probably best to wait until https://github.com/ziglang/zig/issues/10248 |
| 1730 | 1731 | // is implemented in the frontend before implementing them here in the wasm backend. |
src/arch/x86_64/CodeGen.zig+10| ... | ... | @@ -727,6 +727,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 727 | 727 | .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst), |
| 728 | 728 | .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), |
| 729 | 729 | .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), |
| 730 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), | |
| 730 | 731 | |
| 731 | 732 | .wrap_optional => try self.airWrapOptional(inst), |
| 732 | 733 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | ... | @@ -1620,6 +1621,15 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1620 | 1621 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1621 | 1622 | } |
| 1622 | 1623 | |
| 1624 | fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | |
| 1625 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | |
| 1626 | const result: MCValue = if (self.liveness.isUnused(inst)) | |
| 1627 | .dead | |
| 1628 | else | |
| 1629 | return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch}); | |
| 1630 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | |
| 1631 | } | |
| 1632 | ||
| 1623 | 1633 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1624 | 1634 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1625 | 1635 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
src/codegen/c.zig+22-11| ... | ... | @@ -1753,6 +1753,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1753 | 1753 | .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst), |
| 1754 | 1754 | .wrap_errunion_payload => try airWrapErrUnionPay(f, inst), |
| 1755 | 1755 | .wrap_errunion_err => try airWrapErrUnionErr(f, inst), |
| 1756 | .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst), | |
| 1756 | 1757 | // zig fmt: on |
| 1757 | 1758 | }; |
| 1758 | 1759 | switch (result_value) { |
| ... | ... | @@ -3090,17 +3091,18 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3090 | 3091 | const operand = try f.resolveInst(ty_op.operand); |
| 3091 | 3092 | const operand_ty = f.air.typeOf(ty_op.operand); |
| 3092 | 3093 | |
| 3093 | const payload_ty = operand_ty.errorUnionPayload(); | |
| 3094 | if (!payload_ty.hasRuntimeBits()) { | |
| 3095 | if (operand_ty.zigTypeTag() == .Pointer) { | |
| 3096 | const local = try f.allocLocal(inst_ty, .Const); | |
| 3097 | try writer.writeAll(" = *"); | |
| 3098 | try f.writeCValue(writer, operand); | |
| 3099 | try writer.writeAll(";\n"); | |
| 3100 | return local; | |
| 3101 | } else { | |
| 3094 | if (operand_ty.zigTypeTag() == .Pointer) { | |
| 3095 | if (!operand_ty.childType().errorUnionPayload().hasRuntimeBits()) { | |
| 3102 | 3096 | return operand; |
| 3103 | 3097 | } |
| 3098 | const local = try f.allocLocal(inst_ty, .Const); | |
| 3099 | try writer.writeAll(" = *"); | |
| 3100 | try f.writeCValue(writer, operand); | |
| 3101 | try writer.writeAll(";\n"); | |
| 3102 | return local; | |
| 3103 | } | |
| 3104 | if (!operand_ty.errorUnionPayload().hasRuntimeBits()) { | |
| 3105 | return operand; | |
| 3104 | 3106 | } |
| 3105 | 3107 | |
| 3106 | 3108 | const local = try f.allocLocal(inst_ty, .Const); |
| ... | ... | @@ -3123,8 +3125,11 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons |
| 3123 | 3125 | const operand = try f.resolveInst(ty_op.operand); |
| 3124 | 3126 | const operand_ty = f.air.typeOf(ty_op.operand); |
| 3125 | 3127 | |
| 3126 | const payload_ty = operand_ty.errorUnionPayload(); | |
| 3127 | if (!payload_ty.hasRuntimeBits()) { | |
| 3128 | const error_union_ty = if (operand_ty.zigTypeTag() == .Pointer) | |
| 3129 | operand_ty.childType() | |
| 3130 | else | |
| 3131 | operand_ty; | |
| 3132 | if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) { | |
| 3128 | 3133 | return CValue.none; |
| 3129 | 3134 | } |
| 3130 | 3135 | |
| ... | ... | @@ -3160,6 +3165,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3160 | 3165 | try writer.writeAll("};\n"); |
| 3161 | 3166 | return local; |
| 3162 | 3167 | } |
| 3168 | ||
| 3163 | 3169 | fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3164 | 3170 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 3165 | 3171 | |
| ... | ... | @@ -3179,6 +3185,11 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3179 | 3185 | return local; |
| 3180 | 3186 | } |
| 3181 | 3187 | |
| 3188 | fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { | |
| 3189 | _ = inst; | |
| 3190 | return f.fail("TODO: C backend: implement airErrUnionPayloadPtrSet", .{}); | |
| 3191 | } | |
| 3192 | ||
| 3182 | 3193 | fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3183 | 3194 | if (f.liveness.isUnused(inst)) |
| 3184 | 3195 | return CValue.none; |
src/codegen/llvm.zig+38-4| ... | ... | @@ -2248,6 +2248,7 @@ pub const FuncGen = struct { |
| 2248 | 2248 | .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true), |
| 2249 | 2249 | .unwrap_errunion_err => try self.airErrUnionErr(inst, false), |
| 2250 | 2250 | .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true), |
| 2251 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), | |
| 2251 | 2252 | |
| 2252 | 2253 | .wrap_optional => try self.airWrapOptional(inst), |
| 2253 | 2254 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | ... | @@ -3175,8 +3176,9 @@ pub const FuncGen = struct { |
| 3175 | 3176 | |
| 3176 | 3177 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3177 | 3178 | const operand = try self.resolveInst(ty_op.operand); |
| 3178 | const err_union_ty = self.air.typeOf(ty_op.operand); | |
| 3179 | const payload_ty = err_union_ty.errorUnionPayload(); | |
| 3179 | const result_ty = self.air.getRefType(ty_op.ty); | |
| 3180 | const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty; | |
| 3181 | ||
| 3180 | 3182 | if (!payload_ty.hasRuntimeBits()) return null; |
| 3181 | 3183 | if (operand_is_ptr or isByRef(payload_ty)) { |
| 3182 | 3184 | return self.builder.buildStructGEP(operand, 1, ""); |
| ... | ... | @@ -3195,14 +3197,15 @@ pub const FuncGen = struct { |
| 3195 | 3197 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3196 | 3198 | const operand = try self.resolveInst(ty_op.operand); |
| 3197 | 3199 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 3200 | const err_set_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; | |
| 3198 | 3201 | |
| 3199 | const payload_ty = operand_ty.errorUnionPayload(); | |
| 3202 | const payload_ty = err_set_ty.errorUnionPayload(); | |
| 3200 | 3203 | if (!payload_ty.hasRuntimeBits()) { |
| 3201 | 3204 | if (!operand_is_ptr) return operand; |
| 3202 | 3205 | return self.builder.buildLoad(operand, ""); |
| 3203 | 3206 | } |
| 3204 | 3207 | |
| 3205 | if (operand_is_ptr or isByRef(payload_ty)) { | |
| 3208 | if (operand_is_ptr or isByRef(err_set_ty)) { | |
| 3206 | 3209 | const err_field_ptr = self.builder.buildStructGEP(operand, 0, ""); |
| 3207 | 3210 | return self.builder.buildLoad(err_field_ptr, ""); |
| 3208 | 3211 | } |
| ... | ... | @@ -3210,6 +3213,37 @@ pub const FuncGen = struct { |
| 3210 | 3213 | return self.builder.buildExtractValue(operand, 0, ""); |
| 3211 | 3214 | } |
| 3212 | 3215 | |
| 3216 | fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | |
| 3217 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | |
| 3218 | const operand = try self.resolveInst(ty_op.operand); | |
| 3219 | const error_set_ty = self.air.typeOf(ty_op.operand).childType(); | |
| 3220 | ||
| 3221 | const error_ty = error_set_ty.errorUnionSet(); | |
| 3222 | const payload_ty = error_set_ty.errorUnionPayload(); | |
| 3223 | const non_error_val = try self.dg.genTypedValue(.{ .ty = error_ty, .val = Value.zero }); | |
| 3224 | if (!payload_ty.hasRuntimeBits()) { | |
| 3225 | // We have a pointer to a i1. We need to set it to 1 and then return the same pointer. | |
| 3226 | _ = self.builder.buildStore(non_error_val, operand); | |
| 3227 | return operand; | |
| 3228 | } | |
| 3229 | const index_type = self.context.intType(32); | |
| 3230 | { | |
| 3231 | // First set the non-error value. | |
| 3232 | const indices: [2]*const llvm.Value = .{ | |
| 3233 | index_type.constNull(), // dereference the pointer | |
| 3234 | index_type.constNull(), // first field is the payload | |
| 3235 | }; | |
| 3236 | const non_null_ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, ""); | |
| 3237 | _ = self.builder.buildStore(non_error_val, non_null_ptr); | |
| 3238 | } | |
| 3239 | // Then return the payload pointer. | |
| 3240 | const indices: [2]*const llvm.Value = .{ | |
| 3241 | index_type.constNull(), // dereference the pointer | |
| 3242 | index_type.constInt(1, .False), // second field is the payload | |
| 3243 | }; | |
| 3244 | return self.builder.buildInBoundsGEP(operand, &indices, indices.len, ""); | |
| 3245 | } | |
| 3246 | ||
| 3213 | 3247 | fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 3214 | 3248 | if (self.liveness.isUnused(inst)) return null; |
| 3215 | 3249 |
src/print_air.zig+1| ... | ... | @@ -189,6 +189,7 @@ const Writer = struct { |
| 189 | 189 | .optional_payload, |
| 190 | 190 | .optional_payload_ptr, |
| 191 | 191 | .optional_payload_ptr_set, |
| 192 | .errunion_payload_ptr_set, | |
| 192 | 193 | .wrap_optional, |
| 193 | 194 | .unwrap_errunion_payload, |
| 194 | 195 | .unwrap_errunion_err, |
src/print_zir.zig+4| ... | ... | @@ -235,6 +235,10 @@ const Writer = struct { |
| 235 | 235 | .fence, |
| 236 | 236 | .switch_cond, |
| 237 | 237 | .switch_cond_ref, |
| 238 | .array_base_ptr, | |
| 239 | .field_base_ptr, | |
| 240 | .validate_array_init_ty, | |
| 241 | .validate_struct_init_ty, | |
| 238 | 242 | => try self.writeUnNode(stream, inst), |
| 239 | 243 | |
| 240 | 244 | .ref, |
test/behavior.zig+1-1| ... | ... | @@ -119,6 +119,7 @@ test { |
| 119 | 119 | _ = @import("behavior/sizeof_and_typeof.zig"); |
| 120 | 120 | _ = @import("behavior/switch.zig"); |
| 121 | 121 | _ = @import("behavior/widening.zig"); |
| 122 | _ = @import("behavior/bugs/1442.zig"); | |
| 122 | 123 | |
| 123 | 124 | if (builtin.zig_backend == .stage1) { |
| 124 | 125 | // Tests that only pass for the stage1 backend. |
| ... | ... | @@ -135,7 +136,6 @@ test { |
| 135 | 136 | _ = @import("behavior/bugs/920.zig"); |
| 136 | 137 | _ = @import("behavior/bugs/1120.zig"); |
| 137 | 138 | _ = @import("behavior/bugs/1421.zig"); |
| 138 | _ = @import("behavior/bugs/1442.zig"); | |
| 139 | 139 | _ = @import("behavior/bugs/1607.zig"); |
| 140 | 140 | _ = @import("behavior/bugs/1851.zig"); |
| 141 | 141 | _ = @import("behavior/bugs/2114.zig"); |
test/behavior/struct.zig+61| ... | ... | @@ -1199,3 +1199,64 @@ test "for loop over pointers to struct, getting field from struct pointer" { |
| 1199 | 1199 | }; |
| 1200 | 1200 | try S.doTheTest(); |
| 1201 | 1201 | } |
| 1202 | ||
| 1203 | test "anon init through error unions and optionals" { | |
| 1204 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 1205 | if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO | |
| 1206 | ||
| 1207 | const S = struct { | |
| 1208 | a: u32, | |
| 1209 | ||
| 1210 | fn foo() anyerror!?anyerror!@This() { | |
| 1211 | return .{ .a = 1 }; | |
| 1212 | } | |
| 1213 | fn bar() ?anyerror![2]u8 { | |
| 1214 | return .{ 1, 2 }; | |
| 1215 | } | |
| 1216 | ||
| 1217 | fn doTheTest() !void { | |
| 1218 | var a = try (try foo()).?; | |
| 1219 | var b = try bar().?; | |
| 1220 | try expect(a.a + b[1] == 3); | |
| 1221 | } | |
| 1222 | }; | |
| 1223 | ||
| 1224 | try S.doTheTest(); | |
| 1225 | comptime try S.doTheTest(); | |
| 1226 | } | |
| 1227 | ||
| 1228 | test "anon init through optional" { | |
| 1229 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 1230 | if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO | |
| 1231 | ||
| 1232 | const S = struct { | |
| 1233 | a: u32, | |
| 1234 | ||
| 1235 | fn doTheTest() !void { | |
| 1236 | var s: ?@This() = null; | |
| 1237 | s = .{ .a = 1 }; | |
| 1238 | try expect(s.?.a == 1); | |
| 1239 | } | |
| 1240 | }; | |
| 1241 | ||
| 1242 | try S.doTheTest(); | |
| 1243 | comptime try S.doTheTest(); | |
| 1244 | } | |
| 1245 | ||
| 1246 | test "anon init through error union" { | |
| 1247 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 1248 | if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO | |
| 1249 | ||
| 1250 | const S = struct { | |
| 1251 | a: u32, | |
| 1252 | ||
| 1253 | fn doTheTest() !void { | |
| 1254 | var s: anyerror!@This() = error.Foo; | |
| 1255 | s = .{ .a = 1 }; | |
| 1256 | try expect((try s).a == 1); | |
| 1257 | } | |
| 1258 | }; | |
| 1259 | ||
| 1260 | try S.doTheTest(); | |
| 1261 | comptime try S.doTheTest(); | |
| 1262 | } |