| ... | ... | @@ -19931,7 +19931,7 @@ fn coerce( |
| 19931 | 19931 | if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item; |
| 19932 | 19932 | switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { |
| 19933 | 19933 | .ok => {}, |
| 19934 | | .no_match => break :single_item, |
| 19934 | else => break :single_item, |
| 19935 | 19935 | } |
| 19936 | 19936 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); |
| 19937 | 19937 | } |
| ... | ... | @@ -19951,7 +19951,7 @@ fn coerce( |
| 19951 | 19951 | const dst_elem_type = dest_info.pointee_type; |
| 19952 | 19952 | switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src)) { |
| 19953 | 19953 | .ok => {}, |
| 19954 | | .no_match => break :src_array_ptr, |
| 19954 | else => break :src_array_ptr, |
| 19955 | 19955 | } |
| 19956 | 19956 | |
| 19957 | 19957 | switch (dest_info.size) { |
| ... | ... | @@ -19990,7 +19990,7 @@ fn coerce( |
| 19990 | 19990 | const dst_elem_type = dest_info.pointee_type; |
| 19991 | 19991 | switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { |
| 19992 | 19992 | .ok => {}, |
| 19993 | | .no_match => break :src_c_ptr, |
| 19993 | else => break :src_c_ptr, |
| 19994 | 19994 | } |
| 19995 | 19995 | // TODO add safety check for null pointer |
| 19996 | 19996 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); |
| ... | ... | @@ -20034,7 +20034,7 @@ fn coerce( |
| 20034 | 20034 | inst_src, |
| 20035 | 20035 | )) { |
| 20036 | 20036 | .ok => {}, |
| 20037 | | .no_match => break :p, |
| 20037 | else => break :p, |
| 20038 | 20038 | } |
| 20039 | 20039 | if (inst_info.size == .Slice) { |
| 20040 | 20040 | if (dest_info.sentinel == null or inst_info.sentinel == null or |
| ... | ... | @@ -20124,7 +20124,7 @@ fn coerce( |
| 20124 | 20124 | inst_src, |
| 20125 | 20125 | )) { |
| 20126 | 20126 | .ok => {}, |
| 20127 | | .no_match => break :p, |
| 20127 | else => break :p, |
| 20128 | 20128 | } |
| 20129 | 20129 | |
| 20130 | 20130 | if (dest_info.sentinel == null or inst_info.sentinel == null or |
| ... | ... | @@ -20356,14 +20356,348 @@ fn coerce( |
| 20356 | 20356 | return sema.addConstUndef(dest_ty); |
| 20357 | 20357 | } |
| 20358 | 20358 | |
| 20359 | | return sema.fail(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) }); |
| 20359 | const msg = msg: { |
| 20360 | const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) }); |
| 20361 | errdefer msg.destroy(sema.gpa); |
| 20362 | |
| 20363 | try in_memory_result.report(sema, block, inst_src, msg); |
| 20364 | break :msg msg; |
| 20365 | }; |
| 20366 | return sema.failWithOwnedErrorMsg(block, msg); |
| 20360 | 20367 | } |
| 20361 | 20368 | |
| 20362 | | const InMemoryCoercionResult = enum { |
| 20369 | const InMemoryCoercionResult = union(enum) { |
| 20363 | 20370 | ok, |
| 20364 | | no_match, |
| 20371 | no_match: Pair, |
| 20372 | int_mismatch: Int, |
| 20373 | error_union_payload: PairAndChild, |
| 20374 | array_len: IntPair, |
| 20375 | array_sentinel: Sentinel, |
| 20376 | array_elem: PairAndChild, |
| 20377 | vector_len: IntPair, |
| 20378 | vector_elem: PairAndChild, |
| 20379 | optional_shape: Pair, |
| 20380 | optional_child: PairAndChild, |
| 20381 | from_anyerror, |
| 20382 | missing_error: []const []const u8, |
| 20383 | /// true if wanted is var args |
| 20384 | fn_var_args: bool, |
| 20385 | /// true if wanted is generic |
| 20386 | fn_generic: bool, |
| 20387 | fn_param_count: IntPair, |
| 20388 | fn_param_noalias: IntPair, |
| 20389 | fn_param_comptime: ComptimeParam, |
| 20390 | fn_param: Param, |
| 20391 | fn_cc: CC, |
| 20392 | fn_return_type: PairAndChild, |
| 20393 | ptr_child: PairAndChild, |
| 20394 | ptr_addrspace: AddressSpace, |
| 20395 | ptr_sentinel: Sentinel, |
| 20396 | ptr_size: Size, |
| 20397 | ptr_qualifiers: Qualifiers, |
| 20398 | ptr_allowzero: Pair, |
| 20399 | ptr_bit_range: BitRange, |
| 20400 | ptr_alignment: IntPair, |
| 20401 | |
| 20402 | const Pair = struct { |
| 20403 | actual: Type, |
| 20404 | wanted: Type, |
| 20405 | }; |
| 20406 | |
| 20407 | const PairAndChild = struct { |
| 20408 | child: *InMemoryCoercionResult, |
| 20409 | actual: Type, |
| 20410 | wanted: Type, |
| 20411 | }; |
| 20412 | |
| 20413 | const Param = struct { |
| 20414 | child: *InMemoryCoercionResult, |
| 20415 | actual: Type, |
| 20416 | wanted: Type, |
| 20417 | index: u64, |
| 20418 | }; |
| 20419 | |
| 20420 | const ComptimeParam = struct { |
| 20421 | index: u64, |
| 20422 | wanted: bool, |
| 20423 | }; |
| 20424 | |
| 20425 | const Sentinel = struct { |
| 20426 | // unreachable_value indicates no sentinel |
| 20427 | actual: Value, |
| 20428 | wanted: Value, |
| 20429 | ty: Type, |
| 20430 | }; |
| 20431 | |
| 20432 | const Int = struct { |
| 20433 | actual_signedness: std.builtin.Signedness, |
| 20434 | wanted_signedness: std.builtin.Signedness, |
| 20435 | actual_bits: u16, |
| 20436 | wanted_bits: u16, |
| 20437 | }; |
| 20438 | |
| 20439 | const IntPair = struct { |
| 20440 | actual: u64, |
| 20441 | wanted: u64, |
| 20442 | }; |
| 20443 | |
| 20444 | const Size = struct { |
| 20445 | actual: std.builtin.Type.Pointer.Size, |
| 20446 | wanted: std.builtin.Type.Pointer.Size, |
| 20447 | }; |
| 20448 | |
| 20449 | const Qualifiers = struct { |
| 20450 | actual_const: bool, |
| 20451 | wanted_const: bool, |
| 20452 | actual_volatile: bool, |
| 20453 | wanted_volatile: bool, |
| 20454 | }; |
| 20455 | |
| 20456 | const AddressSpace = struct { |
| 20457 | actual: std.builtin.AddressSpace, |
| 20458 | wanted: std.builtin.AddressSpace, |
| 20459 | }; |
| 20460 | |
| 20461 | const CC = struct { |
| 20462 | actual: std.builtin.CallingConvention, |
| 20463 | wanted: std.builtin.CallingConvention, |
| 20464 | }; |
| 20465 | |
| 20466 | const BitRange = struct { |
| 20467 | actual_host: u16, |
| 20468 | wanted_host: u16, |
| 20469 | actual_offset: u16, |
| 20470 | wanted_offset: u16, |
| 20471 | }; |
| 20472 | |
| 20473 | fn dupe(child: *const InMemoryCoercionResult, arena: Allocator) !*InMemoryCoercionResult { |
| 20474 | const res = try arena.create(InMemoryCoercionResult); |
| 20475 | res.* = child.*; |
| 20476 | return res; |
| 20477 | } |
| 20478 | |
| 20479 | fn report(res: *const InMemoryCoercionResult, sema: *Sema, block: *Block, src: LazySrcLoc, msg: *Module.ErrorMsg) !void { |
| 20480 | var cur = res; |
| 20481 | while (true) switch (cur.*) { |
| 20482 | .ok => unreachable, |
| 20483 | .no_match => |types| { |
| 20484 | try sema.addDeclaredHereNote(msg, types.wanted); |
| 20485 | try sema.addDeclaredHereNote(msg, types.actual); |
| 20486 | break; |
| 20487 | }, |
| 20488 | .int_mismatch => |int| { |
| 20489 | try sema.errNote(block, src, msg, "{s} {d}-bit int cannot represent all possible {s} {d}-bit values", .{ |
| 20490 | @tagName(int.wanted_signedness), int.wanted_bits, @tagName(int.actual_signedness), int.actual_bits, |
| 20491 | }); |
| 20492 | break; |
| 20493 | }, |
| 20494 | .error_union_payload => |pair| { |
| 20495 | try sema.errNote(block, src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{ |
| 20496 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20497 | }); |
| 20498 | cur = pair.child; |
| 20499 | }, |
| 20500 | .array_len => |lens| { |
| 20501 | try sema.errNote(block, src, msg, "array of length {d} cannot cast into an array of length {d}", .{ |
| 20502 | lens.actual, lens.wanted, |
| 20503 | }); |
| 20504 | break; |
| 20505 | }, |
| 20506 | .array_sentinel => |sentinel| { |
| 20507 | if (sentinel.actual.tag() != .unreachable_value) { |
| 20508 | try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{ |
| 20509 | sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod), |
| 20510 | }); |
| 20511 | } else { |
| 20512 | try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{ |
| 20513 | sentinel.wanted.fmtValue(sentinel.ty, sema.mod), |
| 20514 | }); |
| 20515 | } |
| 20516 | break; |
| 20517 | }, |
| 20518 | .array_elem => |pair| { |
| 20519 | try sema.errNote(block, src, msg, "array element type '{}' cannot cast into array element type '{}'", .{ |
| 20520 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20521 | }); |
| 20522 | cur = pair.child; |
| 20523 | }, |
| 20524 | .vector_len => |lens| { |
| 20525 | try sema.errNote(block, src, msg, "vector of length {d} cannot cast into a vector of length {d}", .{ |
| 20526 | lens.actual, lens.wanted, |
| 20527 | }); |
| 20528 | break; |
| 20529 | }, |
| 20530 | .vector_elem => |pair| { |
| 20531 | try sema.errNote(block, src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{ |
| 20532 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20533 | }); |
| 20534 | cur = pair.child; |
| 20535 | }, |
| 20536 | .optional_shape => |pair| { |
| 20537 | try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type '{}'", .{ |
| 20538 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20539 | }); |
| 20540 | break; |
| 20541 | }, |
| 20542 | .optional_child => |pair| { |
| 20543 | try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ |
| 20544 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20545 | }); |
| 20546 | cur = pair.child; |
| 20547 | }, |
| 20548 | .from_anyerror => { |
| 20549 | try sema.errNote(block, src, msg, "global error set cannot cast into a smaller set", .{}); |
| 20550 | break; |
| 20551 | }, |
| 20552 | .missing_error => |missing_errors| { |
| 20553 | for (missing_errors) |err| { |
| 20554 | try sema.errNote(block, src, msg, "'error.{s}' not a member of destination error set", .{err}); |
| 20555 | } |
| 20556 | break; |
| 20557 | }, |
| 20558 | .fn_var_args => |wanted_var_args| { |
| 20559 | if (wanted_var_args) { |
| 20560 | try sema.errNote(block, src, msg, "non-variadic function cannot cast into a variadic function", .{}); |
| 20561 | } else { |
| 20562 | try sema.errNote(block, src, msg, "variadic function cannot cast into a non-variadic function", .{}); |
| 20563 | } |
| 20564 | break; |
| 20565 | }, |
| 20566 | .fn_generic => |wanted_generic| { |
| 20567 | if (wanted_generic) { |
| 20568 | try sema.errNote(block, src, msg, "non-generic function cannot cast into a generic function", .{}); |
| 20569 | } else { |
| 20570 | try sema.errNote(block, src, msg, "generic function cannot cast into a non-generic function", .{}); |
| 20571 | } |
| 20572 | break; |
| 20573 | }, |
| 20574 | .fn_param_count => |lens| { |
| 20575 | try sema.errNote(block, src, msg, "function with {d} parameters cannot cast into a function with {d} parameters", .{ |
| 20576 | lens.actual, lens.wanted, |
| 20577 | }); |
| 20578 | break; |
| 20579 | }, |
| 20580 | .fn_param_noalias => |param| { |
| 20581 | var index: u6 = 0; |
| 20582 | var actual_noalias = false; |
| 20583 | while (true) : (index += 1) { |
| 20584 | if (param.actual << index != param.wanted << index) { |
| 20585 | actual_noalias = (param.actual << index) == (1 << 31); |
| 20586 | } |
| 20587 | } |
| 20588 | if (!actual_noalias) { |
| 20589 | try sema.errNote(block, src, msg, "regular paramter {d} cannot cast into a noalias paramter", .{index}); |
| 20590 | } else { |
| 20591 | try sema.errNote(block, src, msg, "noalias paramter {d} cannot cast into a regular paramter", .{index}); |
| 20592 | } |
| 20593 | break; |
| 20594 | }, |
| 20595 | .fn_param_comptime => |param| { |
| 20596 | if (param.wanted) { |
| 20597 | try sema.errNote(block, src, msg, "non-comptime paramter {d} cannot cast into a comptime paramter", .{param.index}); |
| 20598 | } else { |
| 20599 | try sema.errNote(block, src, msg, "comptime paramter {d} cannot cast into a non-comptime paramter", .{param.index}); |
| 20600 | } |
| 20601 | break; |
| 20602 | }, |
| 20603 | .fn_param => |param| { |
| 20604 | try sema.errNote(block, src, msg, "parameter {d} '{}' cannot cast into '{}'", .{ |
| 20605 | param.index, param.actual.fmt(sema.mod), param.wanted.fmt(sema.mod), |
| 20606 | }); |
| 20607 | cur = param.child; |
| 20608 | }, |
| 20609 | .fn_cc => |cc| { |
| 20610 | try sema.errNote(block, src, msg, "calling convention {s} cannot cast into calling convention {s}", .{ @tagName(cc.actual), @tagName(cc.wanted) }); |
| 20611 | break; |
| 20612 | }, |
| 20613 | .fn_return_type => |pair| { |
| 20614 | try sema.errNote(block, src, msg, "return type '{}' cannot cast into return type '{}'", .{ |
| 20615 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20616 | }); |
| 20617 | cur = pair.child; |
| 20618 | }, |
| 20619 | .ptr_child => |pair| { |
| 20620 | try sema.errNote(block, src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{ |
| 20621 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20622 | }); |
| 20623 | cur = pair.child; |
| 20624 | }, |
| 20625 | .ptr_addrspace => |@"addrspace"| { |
| 20626 | try sema.errNote(block, src, msg, "address space '{s}' cannot cast into address space '{s}'", .{ @tagName(@"addrspace".actual), @tagName(@"addrspace".wanted) }); |
| 20627 | break; |
| 20628 | }, |
| 20629 | .ptr_sentinel => |sentinel| { |
| 20630 | if (sentinel.actual.tag() != .unreachable_value) { |
| 20631 | try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{ |
| 20632 | sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod), |
| 20633 | }); |
| 20634 | } else { |
| 20635 | try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{ |
| 20636 | sentinel.wanted.fmtValue(sentinel.ty, sema.mod), |
| 20637 | }); |
| 20638 | } |
| 20639 | break; |
| 20640 | }, |
| 20641 | .ptr_size => |size| { |
| 20642 | try sema.errNote(block, src, msg, "a {s} pointer cannot cast into a {s} pointer", .{ pointerSizeString(size.actual), pointerSizeString(size.wanted) }); |
| 20643 | break; |
| 20644 | }, |
| 20645 | .ptr_qualifiers => |qualifiers| { |
| 20646 | const ok_const = !qualifiers.actual_const or qualifiers.wanted_const; |
| 20647 | const ok_volatile = !qualifiers.actual_volatile or qualifiers.wanted_volatile; |
| 20648 | if (!ok_const) { |
| 20649 | try sema.errNote(block, src, msg, "cast discards const qualifier", .{}); |
| 20650 | } else if (!ok_volatile) { |
| 20651 | try sema.errNote(block, src, msg, "cast discards volatile qualifier", .{}); |
| 20652 | } |
| 20653 | break; |
| 20654 | }, |
| 20655 | .ptr_allowzero => |pair| { |
| 20656 | const wanted_allow_zero = pair.wanted.ptrAllowsZero(); |
| 20657 | const actual_allow_zero = pair.actual.ptrAllowsZero(); |
| 20658 | if (actual_allow_zero and !wanted_allow_zero) { |
| 20659 | try sema.errNote(block, src, msg, "'{}' could have null values which are illegal in type '{}'", .{ |
| 20660 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20661 | }); |
| 20662 | } else { |
| 20663 | try sema.errNote(block, src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{ |
| 20664 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20665 | }); |
| 20666 | } |
| 20667 | break; |
| 20668 | }, |
| 20669 | .ptr_bit_range => |bit_range| { |
| 20670 | if (bit_range.actual_host != bit_range.wanted_host) { |
| 20671 | try sema.errNote(block, src, msg, "pointer host size '{}' cannot cast into pointer host size '{}'", .{ |
| 20672 | bit_range.actual_host, bit_range.wanted_host, |
| 20673 | }); |
| 20674 | } |
| 20675 | if (bit_range.actual_offset != bit_range.wanted_offset) { |
| 20676 | try sema.errNote(block, src, msg, "pointer bit offset '{}' cannot cast into pointer bit offset '{}'", .{ |
| 20677 | bit_range.actual_offset, bit_range.wanted_offset, |
| 20678 | }); |
| 20679 | } |
| 20680 | break; |
| 20681 | }, |
| 20682 | .ptr_alignment => |pair| { |
| 20683 | try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{ |
| 20684 | pair.actual, pair.wanted, |
| 20685 | }); |
| 20686 | break; |
| 20687 | }, |
| 20688 | }; |
| 20689 | } |
| 20365 | 20690 | }; |
| 20366 | 20691 | |
| 20692 | fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 { |
| 20693 | return switch (size) { |
| 20694 | .One => "single", |
| 20695 | .Many => "many", |
| 20696 | .C => "C", |
| 20697 | .Slice => unreachable, |
| 20698 | }; |
| 20699 | } |
| 20700 | |
| 20367 | 20701 | /// If pointers have the same representation in runtime memory, a bitcast AIR instruction |
| 20368 | 20702 | /// may be used for the coercion. |
| 20369 | 20703 | /// * `const` attribute can be gained |
| ... | ... | @@ -20373,8 +20707,6 @@ const InMemoryCoercionResult = enum { |
| 20373 | 20707 | /// * bit offset attributes must match exactly |
| 20374 | 20708 | /// * `*`/`[*]` must match exactly, but `[*c]` matches either one |
| 20375 | 20709 | /// * sentinel-terminated pointers can coerce into `[*]` |
| 20376 | | /// TODO improve this function to report recursive compile errors like it does in stage1. |
| 20377 | | /// look at the function types_match_const_cast_only |
| 20378 | 20710 | fn coerceInMemoryAllowed( |
| 20379 | 20711 | sema: *Sema, |
| 20380 | 20712 | block: *Block, |
| ... | ... | @@ -20392,11 +20724,17 @@ fn coerceInMemoryAllowed( |
| 20392 | 20724 | if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) { |
| 20393 | 20725 | const dest_info = dest_ty.intInfo(target); |
| 20394 | 20726 | const src_info = src_ty.intInfo(target); |
| 20395 | | if (dest_info.signedness == src_info.signedness and |
| 20396 | | dest_info.bits == src_info.bits) |
| 20727 | if (dest_info.signedness != src_info.signedness or |
| 20728 | dest_info.bits != src_info.bits) |
| 20397 | 20729 | { |
| 20398 | | return .ok; |
| 20730 | return InMemoryCoercionResult{ .int_mismatch = .{ |
| 20731 | .actual_signedness = src_info.signedness, |
| 20732 | .wanted_signedness = dest_info.signedness, |
| 20733 | .actual_bits = src_info.bits, |
| 20734 | .wanted_bits = dest_info.bits, |
| 20735 | } }; |
| 20399 | 20736 | } |
| 20737 | return .ok; |
| 20400 | 20738 | } |
| 20401 | 20739 | |
| 20402 | 20740 | // Differently-named floats with the same number of bits. |
| ... | ... | @@ -20434,9 +20772,15 @@ fn coerceInMemoryAllowed( |
| 20434 | 20772 | |
| 20435 | 20773 | // Error Unions |
| 20436 | 20774 | if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) { |
| 20437 | | const child = try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target, dest_src, src_src); |
| 20438 | | if (child == .no_match) { |
| 20439 | | return child; |
| 20775 | const dest_payload = dest_ty.errorUnionPayload(); |
| 20776 | const src_payload = src_ty.errorUnionPayload(); |
| 20777 | const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src); |
| 20778 | if (child != .ok) { |
| 20779 | return InMemoryCoercionResult{ .error_union_payload = .{ |
| 20780 | .child = try child.dupe(sema.arena), |
| 20781 | .actual = src_payload, |
| 20782 | .wanted = dest_payload, |
| 20783 | } }; |
| 20440 | 20784 | } |
| 20441 | 20785 | return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target, dest_src, src_src); |
| 20442 | 20786 | } |
| ... | ... | @@ -20447,57 +20791,89 @@ fn coerceInMemoryAllowed( |
| 20447 | 20791 | } |
| 20448 | 20792 | |
| 20449 | 20793 | // Arrays |
| 20450 | | if (dest_tag == .Array and src_tag == .Array) arrays: { |
| 20794 | if (dest_tag == .Array and src_tag == .Array) { |
| 20451 | 20795 | const dest_info = dest_ty.arrayInfo(); |
| 20452 | 20796 | const src_info = src_ty.arrayInfo(); |
| 20453 | | if (dest_info.len != src_info.len) break :arrays; |
| 20797 | if (dest_info.len != src_info.len) { |
| 20798 | return InMemoryCoercionResult{ .array_len = .{ |
| 20799 | .actual = src_info.len, |
| 20800 | .wanted = dest_info.len, |
| 20801 | } }; |
| 20802 | } |
| 20454 | 20803 | |
| 20455 | 20804 | const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src); |
| 20456 | | if (child == .no_match) { |
| 20457 | | return child; |
| 20805 | if (child != .ok) { |
| 20806 | return InMemoryCoercionResult{ .array_elem = .{ |
| 20807 | .child = try child.dupe(sema.arena), |
| 20808 | .actual = src_info.elem_type, |
| 20809 | .wanted = dest_info.elem_type, |
| 20810 | } }; |
| 20458 | 20811 | } |
| 20459 | 20812 | const ok_sent = dest_info.sentinel == null or |
| 20460 | 20813 | (src_info.sentinel != null and |
| 20461 | 20814 | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, sema.mod)); |
| 20462 | 20815 | if (!ok_sent) { |
| 20463 | | return .no_match; |
| 20816 | return InMemoryCoercionResult{ .array_sentinel = .{ |
| 20817 | .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), |
| 20818 | .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), |
| 20819 | .ty = dest_info.elem_type, |
| 20820 | } }; |
| 20464 | 20821 | } |
| 20465 | 20822 | return .ok; |
| 20466 | 20823 | } |
| 20467 | 20824 | |
| 20468 | 20825 | // Vectors |
| 20469 | | if (dest_tag == .Vector and src_tag == .Vector) vectors: { |
| 20826 | if (dest_tag == .Vector and src_tag == .Vector) { |
| 20470 | 20827 | const dest_len = dest_ty.vectorLen(); |
| 20471 | 20828 | const src_len = src_ty.vectorLen(); |
| 20472 | | if (dest_len != src_len) break :vectors; |
| 20829 | if (dest_len != src_len) { |
| 20830 | return InMemoryCoercionResult{ .vector_len = .{ |
| 20831 | .actual = src_len, |
| 20832 | .wanted = dest_len, |
| 20833 | } }; |
| 20834 | } |
| 20473 | 20835 | |
| 20474 | 20836 | const dest_elem_ty = dest_ty.scalarType(); |
| 20475 | 20837 | const src_elem_ty = src_ty.scalarType(); |
| 20476 | 20838 | const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src); |
| 20477 | | if (child == .no_match) break :vectors; |
| 20839 | if (child != .ok) { |
| 20840 | return InMemoryCoercionResult{ .vector_elem = .{ |
| 20841 | .child = try child.dupe(sema.arena), |
| 20842 | .actual = src_elem_ty, |
| 20843 | .wanted = dest_elem_ty, |
| 20844 | } }; |
| 20845 | } |
| 20478 | 20846 | |
| 20479 | 20847 | return .ok; |
| 20480 | 20848 | } |
| 20481 | 20849 | |
| 20482 | 20850 | // Optionals |
| 20483 | | if (dest_tag == .Optional and src_tag == .Optional) optionals: { |
| 20851 | if (dest_tag == .Optional and src_tag == .Optional) { |
| 20484 | 20852 | if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { |
| 20485 | | // TODO "optional type child '{}' cannot cast into optional type '{}'" |
| 20486 | | return .no_match; |
| 20853 | return InMemoryCoercionResult{ .optional_shape = .{ |
| 20854 | .actual = src_ty, |
| 20855 | .wanted = dest_ty, |
| 20856 | } }; |
| 20487 | 20857 | } |
| 20488 | 20858 | const dest_child_type = dest_ty.optionalChild(&dest_buf); |
| 20489 | 20859 | const src_child_type = src_ty.optionalChild(&src_buf); |
| 20490 | 20860 | |
| 20491 | 20861 | const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src); |
| 20492 | | if (child == .no_match) { |
| 20493 | | // TODO "optional type child '{}' cannot cast into optional type child '{}'" |
| 20494 | | break :optionals; |
| 20862 | if (child != .ok) { |
| 20863 | return InMemoryCoercionResult{ .optional_child = .{ |
| 20864 | .child = try child.dupe(sema.arena), |
| 20865 | .actual = src_child_type, |
| 20866 | .wanted = dest_child_type, |
| 20867 | } }; |
| 20495 | 20868 | } |
| 20496 | 20869 | |
| 20497 | 20870 | return .ok; |
| 20498 | 20871 | } |
| 20499 | 20872 | |
| 20500 | | return .no_match; |
| 20873 | return InMemoryCoercionResult{ .no_match = .{ |
| 20874 | .actual = dest_ty, |
| 20875 | .wanted = src_ty, |
| 20876 | } }; |
| 20501 | 20877 | } |
| 20502 | 20878 | |
| 20503 | 20879 | fn coerceInMemoryAllowedErrorSets( |
| ... | ... | @@ -20564,6 +20940,9 @@ fn coerceInMemoryAllowedErrorSets( |
| 20564 | 20940 | } |
| 20565 | 20941 | } |
| 20566 | 20942 | |
| 20943 | var missing_error_buf = std.ArrayList([]const u8).init(sema.gpa); |
| 20944 | defer missing_error_buf.deinit(); |
| 20945 | |
| 20567 | 20946 | switch (src_ty.tag()) { |
| 20568 | 20947 | .error_set_inferred => { |
| 20569 | 20948 | const src_data = src_ty.castTag(.error_set_inferred).?.data; |
| ... | ... | @@ -20572,15 +20951,21 @@ fn coerceInMemoryAllowedErrorSets( |
| 20572 | 20951 | // src anyerror status might have changed after the resolution. |
| 20573 | 20952 | if (src_ty.isAnyError()) { |
| 20574 | 20953 | // dest_ty.isAnyError() == true is already checked for at this point. |
| 20575 | | return .no_match; |
| 20954 | return .from_anyerror; |
| 20576 | 20955 | } |
| 20577 | 20956 | |
| 20578 | 20957 | for (src_data.errors.keys()) |key| { |
| 20579 | 20958 | if (!dest_ty.errorSetHasField(key)) { |
| 20580 | | return .no_match; |
| 20959 | try missing_error_buf.append(key); |
| 20581 | 20960 | } |
| 20582 | 20961 | } |
| 20583 | 20962 | |
| 20963 | if (missing_error_buf.items.len != 0) { |
| 20964 | return InMemoryCoercionResult{ |
| 20965 | .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), |
| 20966 | }; |
| 20967 | } |
| 20968 | |
| 20584 | 20969 | return .ok; |
| 20585 | 20970 | }, |
| 20586 | 20971 | .error_set_single => { |
| ... | ... | @@ -20588,37 +20973,52 @@ fn coerceInMemoryAllowedErrorSets( |
| 20588 | 20973 | if (dest_ty.errorSetHasField(name)) { |
| 20589 | 20974 | return .ok; |
| 20590 | 20975 | } |
| 20976 | const list = try sema.arena.alloc([]const u8, 1); |
| 20977 | list[0] = name; |
| 20978 | return InMemoryCoercionResult{ .missing_error = list }; |
| 20591 | 20979 | }, |
| 20592 | 20980 | .error_set_merged => { |
| 20593 | 20981 | const names = src_ty.castTag(.error_set_merged).?.data.keys(); |
| 20594 | 20982 | for (names) |name| { |
| 20595 | 20983 | if (!dest_ty.errorSetHasField(name)) { |
| 20596 | | return .no_match; |
| 20984 | try missing_error_buf.append(name); |
| 20597 | 20985 | } |
| 20598 | 20986 | } |
| 20599 | 20987 | |
| 20988 | if (missing_error_buf.items.len != 0) { |
| 20989 | return InMemoryCoercionResult{ |
| 20990 | .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), |
| 20991 | }; |
| 20992 | } |
| 20993 | |
| 20600 | 20994 | return .ok; |
| 20601 | 20995 | }, |
| 20602 | 20996 | .error_set => { |
| 20603 | 20997 | const names = src_ty.castTag(.error_set).?.data.names.keys(); |
| 20604 | 20998 | for (names) |name| { |
| 20605 | 20999 | if (!dest_ty.errorSetHasField(name)) { |
| 20606 | | return .no_match; |
| 21000 | try missing_error_buf.append(name); |
| 20607 | 21001 | } |
| 20608 | 21002 | } |
| 20609 | 21003 | |
| 21004 | if (missing_error_buf.items.len != 0) { |
| 21005 | return InMemoryCoercionResult{ |
| 21006 | .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), |
| 21007 | }; |
| 21008 | } |
| 21009 | |
| 20610 | 21010 | return .ok; |
| 20611 | 21011 | }, |
| 20612 | 21012 | .anyerror => switch (dest_ty.tag()) { |
| 20613 | | .error_set_inferred => return .no_match, // Caught by dest.isAnyError() above. |
| 20614 | | .error_set_single, .error_set_merged, .error_set => {}, |
| 21013 | .error_set_inferred => unreachable, // Caught by dest_ty.isAnyError() above. |
| 21014 | .error_set_single, .error_set_merged, .error_set => return .from_anyerror, |
| 20615 | 21015 | .anyerror => unreachable, // Filtered out above. |
| 20616 | 21016 | else => unreachable, |
| 20617 | 21017 | }, |
| 20618 | 21018 | else => unreachable, |
| 20619 | 21019 | } |
| 20620 | 21020 | |
| 20621 | | return .no_match; |
| 21021 | unreachable; |
| 20622 | 21022 | } |
| 20623 | 21023 | |
| 20624 | 21024 | fn coerceInMemoryAllowedFns( |
| ... | ... | @@ -20634,44 +21034,67 @@ fn coerceInMemoryAllowedFns( |
| 20634 | 21034 | const src_info = src_ty.fnInfo(); |
| 20635 | 21035 | |
| 20636 | 21036 | if (dest_info.is_var_args != src_info.is_var_args) { |
| 20637 | | return .no_match; |
| 21037 | return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args }; |
| 20638 | 21038 | } |
| 20639 | 21039 | |
| 20640 | 21040 | if (dest_info.is_generic != src_info.is_generic) { |
| 20641 | | return .no_match; |
| 21041 | return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic }; |
| 21042 | } |
| 21043 | |
| 21044 | if (dest_info.cc != src_info.cc) { |
| 21045 | return InMemoryCoercionResult{ .fn_cc = .{ |
| 21046 | .actual = src_info.cc, |
| 21047 | .wanted = dest_info.cc, |
| 21048 | } }; |
| 20642 | 21049 | } |
| 20643 | 21050 | |
| 20644 | 21051 | if (!src_info.return_type.isNoReturn()) { |
| 20645 | 21052 | const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type, src_info.return_type, false, target, dest_src, src_src); |
| 20646 | | if (rt == .no_match) { |
| 20647 | | return rt; |
| 21053 | if (rt != .ok) { |
| 21054 | return InMemoryCoercionResult{ .fn_return_type = .{ |
| 21055 | .child = try rt.dupe(sema.arena), |
| 21056 | .actual = src_info.return_type, |
| 21057 | .wanted = dest_info.return_type, |
| 21058 | } }; |
| 20648 | 21059 | } |
| 20649 | 21060 | } |
| 20650 | 21061 | |
| 20651 | 21062 | if (dest_info.param_types.len != src_info.param_types.len) { |
| 20652 | | return .no_match; |
| 21063 | return InMemoryCoercionResult{ .fn_param_count = .{ |
| 21064 | .actual = dest_info.param_types.len, |
| 21065 | .wanted = dest_info.param_types.len, |
| 21066 | } }; |
| 21067 | } |
| 21068 | |
| 21069 | if (dest_info.noalias_bits != src_info.noalias_bits) { |
| 21070 | return InMemoryCoercionResult{ .fn_param_noalias = .{ |
| 21071 | .actual = dest_info.noalias_bits, |
| 21072 | .wanted = dest_info.noalias_bits, |
| 21073 | } }; |
| 20653 | 21074 | } |
| 20654 | 21075 | |
| 20655 | 21076 | for (dest_info.param_types) |dest_param_ty, i| { |
| 20656 | 21077 | const src_param_ty = src_info.param_types[i]; |
| 20657 | 21078 | |
| 20658 | 21079 | if (dest_info.comptime_params[i] != src_info.comptime_params[i]) { |
| 20659 | | return .no_match; |
| 21080 | return InMemoryCoercionResult{ .fn_param_comptime = .{ |
| 21081 | .index = i, |
| 21082 | .wanted = dest_info.comptime_params[i], |
| 21083 | } }; |
| 20660 | 21084 | } |
| 20661 | 21085 | |
| 20662 | | // TODO: noalias |
| 20663 | | |
| 20664 | 21086 | // Note: Cast direction is reversed here. |
| 20665 | 21087 | const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src); |
| 20666 | | if (param == .no_match) { |
| 20667 | | return param; |
| 21088 | if (param != .ok) { |
| 21089 | return InMemoryCoercionResult{ .fn_param = .{ |
| 21090 | .child = try param.dupe(sema.arena), |
| 21091 | .actual = src_param_ty, |
| 21092 | .wanted = dest_param_ty, |
| 21093 | .index = i, |
| 21094 | } }; |
| 20668 | 21095 | } |
| 20669 | 21096 | } |
| 20670 | 21097 | |
| 20671 | | if (dest_info.cc != src_info.cc) { |
| 20672 | | return .no_match; |
| 20673 | | } |
| 20674 | | |
| 20675 | 21098 | return .ok; |
| 20676 | 21099 | } |
| 20677 | 21100 | |
| ... | ... | @@ -20690,26 +21113,13 @@ fn coerceInMemoryAllowedPtrs( |
| 20690 | 21113 | const dest_info = dest_ptr_ty.ptrInfo().data; |
| 20691 | 21114 | const src_info = src_ptr_ty.ptrInfo().data; |
| 20692 | 21115 | |
| 20693 | | const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src); |
| 20694 | | if (child == .no_match) { |
| 20695 | | return child; |
| 20696 | | } |
| 20697 | | |
| 20698 | | if (dest_info.@"addrspace" != src_info.@"addrspace") { |
| 20699 | | return .no_match; |
| 20700 | | } |
| 20701 | | |
| 20702 | | const ok_sent = dest_info.sentinel == null or src_info.size == .C or |
| 20703 | | (src_info.sentinel != null and |
| 20704 | | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod)); |
| 20705 | | if (!ok_sent) { |
| 20706 | | return .no_match; |
| 20707 | | } |
| 20708 | | |
| 20709 | 21116 | const ok_ptr_size = src_info.size == dest_info.size or |
| 20710 | 21117 | src_info.size == .C or dest_info.size == .C; |
| 20711 | 21118 | if (!ok_ptr_size) { |
| 20712 | | return .no_match; |
| 21119 | return InMemoryCoercionResult{ .ptr_size = .{ |
| 21120 | .actual = src_info.size, |
| 21121 | .wanted = dest_info.size, |
| 21122 | } }; |
| 20713 | 21123 | } |
| 20714 | 21124 | |
| 20715 | 21125 | const ok_cv_qualifiers = |
| ... | ... | @@ -20717,7 +21127,28 @@ fn coerceInMemoryAllowedPtrs( |
| 20717 | 21127 | (!src_info.@"volatile" or dest_info.@"volatile"); |
| 20718 | 21128 | |
| 20719 | 21129 | if (!ok_cv_qualifiers) { |
| 20720 | | return .no_match; |
| 21130 | return InMemoryCoercionResult{ .ptr_qualifiers = .{ |
| 21131 | .actual_const = !src_info.mutable, |
| 21132 | .wanted_const = !dest_info.mutable, |
| 21133 | .actual_volatile = src_info.@"volatile", |
| 21134 | .wanted_volatile = dest_info.@"volatile", |
| 21135 | } }; |
| 21136 | } |
| 21137 | |
| 21138 | if (dest_info.@"addrspace" != src_info.@"addrspace") { |
| 21139 | return InMemoryCoercionResult{ .ptr_addrspace = .{ |
| 21140 | .actual = src_info.@"addrspace", |
| 21141 | .wanted = dest_info.@"addrspace", |
| 21142 | } }; |
| 21143 | } |
| 21144 | |
| 21145 | const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src); |
| 21146 | if (child != .ok) { |
| 21147 | return InMemoryCoercionResult{ .ptr_child = .{ |
| 21148 | .child = try child.dupe(sema.arena), |
| 21149 | .actual = src_info.pointee_type, |
| 21150 | .wanted = dest_info.pointee_type, |
| 21151 | } }; |
| 20721 | 21152 | } |
| 20722 | 21153 | |
| 20723 | 21154 | const dest_allow_zero = dest_ty.ptrAllowsZero(); |
| ... | ... | @@ -20727,13 +21158,32 @@ fn coerceInMemoryAllowedPtrs( |
| 20727 | 21158 | (src_allow_zero or !dest_is_mut)) or |
| 20728 | 21159 | (!dest_allow_zero and !src_allow_zero); |
| 20729 | 21160 | if (!ok_allows_zero) { |
| 20730 | | return .no_match; |
| 21161 | return InMemoryCoercionResult{ .ptr_allowzero = .{ |
| 21162 | .actual = src_ty, |
| 21163 | .wanted = dest_ty, |
| 21164 | } }; |
| 20731 | 21165 | } |
| 20732 | 21166 | |
| 20733 | 21167 | if (src_info.host_size != dest_info.host_size or |
| 20734 | 21168 | src_info.bit_offset != dest_info.bit_offset) |
| 20735 | 21169 | { |
| 20736 | | return .no_match; |
| 21170 | return InMemoryCoercionResult{ .ptr_bit_range = .{ |
| 21171 | .actual_host = src_info.host_size, |
| 21172 | .wanted_host = dest_info.host_size, |
| 21173 | .actual_offset = src_info.bit_offset, |
| 21174 | .wanted_offset = dest_info.bit_offset, |
| 21175 | } }; |
| 21176 | } |
| 21177 | |
| 21178 | const ok_sent = dest_info.sentinel == null or src_info.size == .C or |
| 21179 | (src_info.sentinel != null and |
| 21180 | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod)); |
| 21181 | if (!ok_sent) { |
| 21182 | return InMemoryCoercionResult{ .ptr_sentinel = .{ |
| 21183 | .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), |
| 21184 | .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), |
| 21185 | .ty = dest_info.pointee_type, |
| 21186 | } }; |
| 20737 | 21187 | } |
| 20738 | 21188 | |
| 20739 | 21189 | // If both pointers have alignment 0, it means they both want ABI alignment. |
| ... | ... | @@ -20758,7 +21208,10 @@ fn coerceInMemoryAllowedPtrs( |
| 20758 | 21208 | dest_info.pointee_type.abiAlignment(target); |
| 20759 | 21209 | |
| 20760 | 21210 | if (dest_align > src_align) { |
| 20761 | | return .no_match; |
| 21211 | return InMemoryCoercionResult{ .ptr_alignment = .{ |
| 21212 | .actual = src_align, |
| 21213 | .wanted = dest_align, |
| 21214 | } }; |
| 20762 | 21215 | } |
| 20763 | 21216 | |
| 20764 | 21217 | break :alignment; |