authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-24 12:06:29-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-24 12:07:14-07:00
logce65ca434584783c30c80b611e02428a26f65512
tree326dc8e23e020b55c3a2901e033bac6b37c7fd7a
parentf7b090d7076a20a614bf20cac05e5e18c06ad18a

stage2: refactor coercePeerTypes and fix C ptr cmp with null


2 files changed, 151 insertions(+), 122 deletions(-)

src/Sema.zig+131-121
...@@ -1233,6 +1233,10 @@ fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: T...@@ -1233,6 +1233,10 @@ fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: T
1233 return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{ lhs_ty, rhs_ty });1233 return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{ lhs_ty, rhs_ty });
1234}1234}
12351235
1236fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, optional_ty: Type) CompileError {
1237 return sema.fail(block, src, "expected optional type, found {}", .{optional_ty});
1238}
1239
1236fn failWithErrorSetCodeMissing(1240fn failWithErrorSetCodeMissing(
1237 sema: *Sema,1241 sema: *Sema,
1238 block: *Block,1242 block: *Block,
...@@ -4636,19 +4640,23 @@ fn zirOptionalPayload(...@@ -4636,19 +4640,23 @@ fn zirOptionalPayload(
4636 const src = inst_data.src();4640 const src = inst_data.src();
4637 const operand = sema.resolveInst(inst_data.operand);4641 const operand = sema.resolveInst(inst_data.operand);
4638 const operand_ty = sema.typeOf(operand);4642 const operand_ty = sema.typeOf(operand);
4639 const opt_type = operand_ty;4643 const result_ty = switch (operand_ty.zigTypeTag()) {
4640 if (opt_type.zigTypeTag() != .Optional) {4644 .Optional => try operand_ty.optionalChildAlloc(sema.arena),
4641 return sema.fail(block, src, "expected optional type, found {}", .{opt_type});4645 .Pointer => t: {
4642 }4646 if (operand_ty.ptrSize() != .C) {
46434647 return sema.failWithExpectedOptionalType(block, src, operand_ty);
4644 const child_type = try opt_type.optionalChildAlloc(sema.arena);4648 }
4649 break :t operand_ty;
4650 },
4651 else => return sema.failWithExpectedOptionalType(block, src, operand_ty),
4652 };
46454653
4646 if (try sema.resolveDefinedValue(block, src, operand)) |val| {4654 if (try sema.resolveDefinedValue(block, src, operand)) |val| {
4647 if (val.isNull()) {4655 if (val.isNull()) {
4648 return sema.fail(block, src, "unable to unwrap null", .{});4656 return sema.fail(block, src, "unable to unwrap null", .{});
4649 }4657 }
4650 const sub_val = val.castTag(.opt_payload).?.data;4658 const sub_val = val.castTag(.opt_payload).?.data;
4651 return sema.addConstant(child_type, sub_val);4659 return sema.addConstant(result_ty, sub_val);
4652 }4660 }
46534661
4654 try sema.requireRuntimeBlock(block, src);4662 try sema.requireRuntimeBlock(block, src);
...@@ -4656,7 +4664,7 @@ fn zirOptionalPayload(...@@ -4656,7 +4664,7 @@ fn zirOptionalPayload(
4656 const is_non_null = try block.addUnOp(.is_non_null, operand);4664 const is_non_null = try block.addUnOp(.is_non_null, operand);
4657 try sema.addSafetyCheck(block, is_non_null, .unwrap_null);4665 try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
4658 }4666 }
4659 return block.addTyOp(.optional_payload, child_type, operand);4667 return block.addTyOp(.optional_payload, result_ty, operand);
4660}4668}
46614669
4662/// Value in, value out4670/// Value in, value out
...@@ -8135,11 +8143,13 @@ fn zirCmpEq(...@@ -8135,11 +8143,13 @@ fn zirCmpEq(
8135 rhs_ty_tag == .Null and lhs_ty_tag == .Optional))8143 rhs_ty_tag == .Null and lhs_ty_tag == .Optional))
8136 {8144 {
8137 // comparing null with optionals8145 // comparing null with optionals
8138 const opt_operand = if (lhs_ty_tag == .Optional) lhs else rhs;8146 const opt_operand = if (lhs_ty_tag == .Null) rhs else lhs;
8139 return sema.analyzeIsNull(block, src, opt_operand, op == .neq);8147 return sema.analyzeIsNull(block, src, opt_operand, op == .neq);
8140 }8148 }
8141 if (((lhs_ty_tag == .Null and rhs_ty.isCPtr()) or (rhs_ty_tag == .Null and lhs_ty.isCPtr()))) {8149 if (((lhs_ty_tag == .Null and rhs_ty.isCPtr()) or (rhs_ty_tag == .Null and lhs_ty.isCPtr()))) {
8142 return sema.fail(block, src, "TODO implement C pointer cmp", .{});8150 // comparing null with C pointers
8151 const opt_operand = if (lhs_ty_tag == .Null) rhs else lhs;
8152 return sema.analyzeIsNull(block, src, opt_operand, op == .neq);
8143 }8153 }
8144 if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {8154 if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
8145 const non_null_type = if (lhs_ty_tag == .Null) rhs_ty else lhs_ty;8155 const non_null_type = if (lhs_ty_tag == .Null) rhs_ty else lhs_ty;
...@@ -13598,127 +13608,127 @@ fn resolvePeerTypes(...@@ -13598,127 +13608,127 @@ fn resolvePeerTypes(
13598 const candidate_ty_tag = candidate_ty.zigTypeTag();13608 const candidate_ty_tag = candidate_ty.zigTypeTag();
13599 const chosen_ty_tag = chosen_ty.zigTypeTag();13609 const chosen_ty_tag = chosen_ty.zigTypeTag();
1360013610
13601 if (candidate_ty_tag == .NoReturn)13611 switch (candidate_ty_tag) {
13602 continue;13612 .NoReturn, .Undefined => continue,
13603 if (chosen_ty_tag == .NoReturn) {
13604 chosen = candidate;
13605 chosen_i = candidate_i + 1;
13606 continue;
13607 }
13608 if (candidate_ty_tag == .Undefined)
13609 continue;
13610 if (chosen_ty_tag == .Undefined) {
13611 chosen = candidate;
13612 chosen_i = candidate_i + 1;
13613 continue;
13614 }
13615 if (chosen_ty.isInt() and
13616 candidate_ty.isInt() and
13617 chosen_ty.isSignedInt() == candidate_ty.isSignedInt())
13618 {
13619 if (chosen_ty.intInfo(target).bits < candidate_ty.intInfo(target).bits) {
13620 chosen = candidate;
13621 chosen_i = candidate_i + 1;
13622 }
13623 continue;
13624 }
13625 if (chosen_ty.isRuntimeFloat() and candidate_ty.isRuntimeFloat()) {
13626 if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) {
13627 chosen = candidate;
13628 chosen_i = candidate_i + 1;
13629 }
13630 continue;
13631 }
1363213613
13633 if (chosen_ty_tag == .ComptimeInt and candidate_ty.isInt()) {13614 .Null => {
13634 chosen = candidate;13615 any_are_null = true;
13635 chosen_i = candidate_i + 1;13616 continue;
13636 continue;13617 },
13637 }
13638
13639 if (chosen_ty.isInt() and candidate_ty_tag == .ComptimeInt) {
13640 continue;
13641 }
13642
13643 if ((chosen_ty_tag == .ComptimeFloat or chosen_ty_tag == .ComptimeInt) and
13644 candidate_ty.isRuntimeFloat())
13645 {
13646 chosen = candidate;
13647 chosen_i = candidate_i + 1;
13648 continue;
13649 }
13650 if (chosen_ty.isRuntimeFloat() and
13651 (candidate_ty_tag == .ComptimeFloat or candidate_ty_tag == .ComptimeInt))
13652 {
13653 continue;
13654 }
13655
13656 if (chosen_ty_tag == .Enum and candidate_ty_tag == .EnumLiteral) {
13657 continue;
13658 }
13659 if (chosen_ty_tag == .EnumLiteral and candidate_ty_tag == .Enum) {
13660 chosen = candidate;
13661 chosen_i = candidate_i + 1;
13662 continue;
13663 }
13664
13665 if (chosen_ty_tag == .Pointer and chosen_ty.ptrSize() == .C and
13666 (candidate_ty_tag == .Int or candidate_ty_tag == .ComptimeInt))
13667 {
13668 continue;
13669 }
13670 if (candidate_ty_tag == .Pointer and candidate_ty.ptrSize() == .C and
13671 (chosen_ty_tag == .Int or chosen_ty_tag == .ComptimeInt))
13672 {
13673 chosen = candidate;
13674 chosen_i = candidate_i + 1;
13675 continue;
13676 }
13677
13678 if (chosen_ty_tag == .ComptimeFloat and candidate_ty_tag == .ComptimeInt)
13679 continue;
13680 if (chosen_ty_tag == .ComptimeInt and candidate_ty_tag == .ComptimeFloat) {
13681 chosen = candidate;
13682 chosen_i = candidate_i + 1;
13683 continue;
13684 }
1368513618
13686 if (chosen_ty_tag == .Null) {13619 .Int => switch (chosen_ty_tag) {
13687 any_are_null = true;13620 .ComptimeInt => {
13688 chosen = candidate;13621 chosen = candidate;
13689 chosen_i = candidate_i + 1;13622 chosen_i = candidate_i + 1;
13690 continue;13623 continue;
13691 }13624 },
13692 if (candidate_ty_tag == .Null) {13625 .Int => {
13693 any_are_null = true;13626 if (chosen_ty.isSignedInt() == candidate_ty.isSignedInt()) {
13694 continue;13627 if (chosen_ty.intInfo(target).bits < candidate_ty.intInfo(target).bits) {
13628 chosen = candidate;
13629 chosen_i = candidate_i + 1;
13630 }
13631 continue;
13632 }
13633 },
13634 .Pointer => if (chosen_ty.ptrSize() == .C) continue,
13635 else => {},
13636 },
13637 .ComptimeInt => switch (chosen_ty_tag) {
13638 .Int, .Float, .ComptimeFloat => continue,
13639 .Pointer => if (chosen_ty.ptrSize() == .C) continue,
13640 else => {},
13641 },
13642 .Float => switch (chosen_ty_tag) {
13643 .Float => {
13644 if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) {
13645 chosen = candidate;
13646 chosen_i = candidate_i + 1;
13647 }
13648 continue;
13649 },
13650 .ComptimeFloat, .ComptimeInt => {
13651 chosen = candidate;
13652 chosen_i = candidate_i + 1;
13653 continue;
13654 },
13655 else => {},
13656 },
13657 .ComptimeFloat => switch (chosen_ty_tag) {
13658 .Float => continue,
13659 .ComptimeInt => {
13660 chosen = candidate;
13661 chosen_i = candidate_i + 1;
13662 continue;
13663 },
13664 else => {},
13665 },
13666 .Enum => switch (chosen_ty_tag) {
13667 .EnumLiteral => {
13668 chosen = candidate;
13669 chosen_i = candidate_i + 1;
13670 continue;
13671 },
13672 else => {},
13673 },
13674 .EnumLiteral => switch (chosen_ty_tag) {
13675 .Enum => continue,
13676 else => {},
13677 },
13678 .Pointer => {
13679 if (candidate_ty.ptrSize() == .C) {
13680 if (chosen_ty_tag == .Int or chosen_ty_tag == .ComptimeInt) {
13681 chosen = candidate;
13682 chosen_i = candidate_i + 1;
13683 continue;
13684 }
13685 if (chosen_ty_tag == .Pointer and chosen_ty.ptrSize() != .Slice) {
13686 continue;
13687 }
13688 }
13689 },
13690 .Optional => {
13691 var opt_child_buf: Type.Payload.ElemType = undefined;
13692 const opt_child_ty = candidate_ty.optionalChild(&opt_child_buf);
13693 if (coerceInMemoryAllowed(opt_child_ty, chosen_ty, false, target) == .ok) {
13694 chosen = candidate;
13695 chosen_i = candidate_i + 1;
13696 continue;
13697 }
13698 if (coerceInMemoryAllowed(chosen_ty, opt_child_ty, false, target) == .ok) {
13699 any_are_null = true;
13700 continue;
13701 }
13702 },
13703 else => {},
13695 }13704 }
1369613705
13697 if (chosen_ty_tag == .Optional) {13706 switch (chosen_ty_tag) {
13698 var opt_child_buf: Type.Payload.ElemType = undefined;13707 .NoReturn, .Undefined => {
13699 const opt_child_ty = chosen_ty.optionalChild(&opt_child_buf);
13700 if (coerceInMemoryAllowed(opt_child_ty, candidate_ty, false, target) == .ok) {
13701 continue;
13702 }
13703 if (coerceInMemoryAllowed(candidate_ty, opt_child_ty, false, target) == .ok) {
13704 any_are_null = true;
13705 chosen = candidate;13708 chosen = candidate;
13706 chosen_i = candidate_i + 1;13709 chosen_i = candidate_i + 1;
13707 continue;13710 continue;
13708 }13711 },
13709 }13712 .Null => {
13710 if (candidate_ty_tag == .Optional) {13713 any_are_null = true;
13711 var opt_child_buf: Type.Payload.ElemType = undefined;
13712 const opt_child_ty = candidate_ty.optionalChild(&opt_child_buf);
13713 if (coerceInMemoryAllowed(opt_child_ty, chosen_ty, false, target) == .ok) {
13714 chosen = candidate;13714 chosen = candidate;
13715 chosen_i = candidate_i + 1;13715 chosen_i = candidate_i + 1;
13716 continue;13716 continue;
13717 }13717 },
13718 if (coerceInMemoryAllowed(chosen_ty, opt_child_ty, false, target) == .ok) {13718 .Optional => {
13719 any_are_null = true;13719 var opt_child_buf: Type.Payload.ElemType = undefined;
13720 continue;13720 const opt_child_ty = chosen_ty.optionalChild(&opt_child_buf);
13721 }13721 if (coerceInMemoryAllowed(opt_child_ty, candidate_ty, false, target) == .ok) {
13722 continue;
13723 }
13724 if (coerceInMemoryAllowed(candidate_ty, opt_child_ty, false, target) == .ok) {
13725 any_are_null = true;
13726 chosen = candidate;
13727 chosen_i = candidate_i + 1;
13728 continue;
13729 }
13730 },
13731 else => {},
13722 }13732 }
1372313733
13724 // At this point, we hit a compile error. We need to recover13734 // At this point, we hit a compile error. We need to recover
src/value.zig+20-1
...@@ -1790,12 +1790,31 @@ pub const Value = extern union {...@@ -1790,12 +1790,31 @@ pub const Value = extern union {
1790 return self.tag() == .undef;1790 return self.tag() == .undef;
1791 }1791 }
17921792
1793 /// Valid for all types. Asserts the value is not undefined and not unreachable.1793 /// Asserts the value is not undefined and not unreachable.
1794 /// Integer value 0 is considered null because of C pointers.
1794 pub fn isNull(self: Value) bool {1795 pub fn isNull(self: Value) bool {
1795 return switch (self.tag()) {1796 return switch (self.tag()) {
1796 .null_value => true,1797 .null_value => true,
1797 .opt_payload => false,1798 .opt_payload => false,
17981799
1800 // If it's not one of those two tags then it must be a C pointer value,
1801 // in which case the value 0 is null and other values are non-null.
1802
1803 .zero,
1804 .bool_false,
1805 .the_only_possible_value,
1806 => true,
1807
1808 .one,
1809 .bool_true,
1810 => false,
1811
1812 .int_u64,
1813 .int_i64,
1814 .int_big_positive,
1815 .int_big_negative,
1816 => compareWithZero(self, .eq),
1817
1799 .undef => unreachable,1818 .undef => unreachable,
1800 .unreachable_value => unreachable,1819 .unreachable_value => unreachable,
1801 .inferred_alloc => unreachable,1820 .inferred_alloc => unreachable,