| ... | @@ -19853,6 +19853,26 @@ fn coerce( | ... | @@ -19853,6 +19853,26 @@ fn coerce( |
| 19853 | inst: Air.Inst.Ref, | 19853 | inst: Air.Inst.Ref, |
| 19854 | inst_src: LazySrcLoc, | 19854 | inst_src: LazySrcLoc, |
| 19855 | ) CompileError!Air.Inst.Ref { | 19855 | ) CompileError!Air.Inst.Ref { |
| | 19856 | return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, true) catch |err| switch (err) { |
| | 19857 | error.NotCoercible => unreachable, |
| | 19858 | else => |e| return e, |
| | 19859 | }; |
| | 19860 | } |
| | 19861 | |
| | 19862 | const CoersionError = CompileError || error{ |
| | 19863 | /// When coerce is called recursively, this error should be returned instead of using `fail` |
| | 19864 | /// to ensure correct types in compile errors. |
| | 19865 | NotCoercible, |
| | 19866 | }; |
| | 19867 | |
| | 19868 | fn coerceExtra( |
| | 19869 | sema: *Sema, |
| | 19870 | block: *Block, |
| | 19871 | dest_ty_unresolved: Type, |
| | 19872 | inst: Air.Inst.Ref, |
| | 19873 | inst_src: LazySrcLoc, |
| | 19874 | report_err: bool, |
| | 19875 | ) CoersionError!Air.Inst.Ref { |
| 19856 | switch (dest_ty_unresolved.tag()) { | 19876 | switch (dest_ty_unresolved.tag()) { |
| 19857 | .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src), | 19877 | .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src), |
| 19858 | .generic_poison => return inst, | 19878 | .generic_poison => return inst, |
| ... | @@ -19869,7 +19889,7 @@ fn coerce( | ... | @@ -19869,7 +19889,7 @@ fn coerce( |
| 19869 | const arena = sema.arena; | 19889 | const arena = sema.arena; |
| 19870 | const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst); | 19890 | const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst); |
| 19871 | | 19891 | |
| 19872 | const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src); | 19892 | var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src); |
| 19873 | if (in_memory_result == .ok) { | 19893 | if (in_memory_result == .ok) { |
| 19874 | if (maybe_inst_val) |val| { | 19894 | if (maybe_inst_val) |val| { |
| 19875 | // Keep the comptime Value representation; take the new type. | 19895 | // Keep the comptime Value representation; take the new type. |
| ... | @@ -19882,7 +19902,7 @@ fn coerce( | ... | @@ -19882,7 +19902,7 @@ fn coerce( |
| 19882 | const is_undef = if (maybe_inst_val) |val| val.isUndef() else false; | 19902 | const is_undef = if (maybe_inst_val) |val| val.isUndef() else false; |
| 19883 | | 19903 | |
| 19884 | switch (dest_ty.zigTypeTag()) { | 19904 | switch (dest_ty.zigTypeTag()) { |
| 19885 | .Optional => { | 19905 | .Optional => optional: { |
| 19886 | // undefined sets the optional bit also to undefined. | 19906 | // undefined sets the optional bit also to undefined. |
| 19887 | if (is_undef) { | 19907 | if (is_undef) { |
| 19888 | return sema.addConstUndef(dest_ty); | 19908 | return sema.addConstUndef(dest_ty); |
| ... | @@ -19903,10 +19923,19 @@ fn coerce( | ... | @@ -19903,10 +19923,19 @@ fn coerce( |
| 19903 | | 19923 | |
| 19904 | // T to ?T | 19924 | // T to ?T |
| 19905 | const child_type = try dest_ty.optionalChildAlloc(sema.arena); | 19925 | const child_type = try dest_ty.optionalChildAlloc(sema.arena); |
| 19906 | const intermediate = try sema.coerce(block, child_type, inst, inst_src); | 19926 | const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, false) catch |err| switch (err) { |
| 19907 | return sema.wrapOptional(block, dest_ty, intermediate, inst_src); | 19927 | error.NotCoercible => { |
| | 19928 | if (in_memory_result == .no_match) { |
| | 19929 | // Try to give more useful notes |
| | 19930 | in_memory_result = try sema.coerceInMemoryAllowed(block, child_type, inst_ty, false, target, dest_ty_src, inst_src); |
| | 19931 | } |
| | 19932 | break :optional; |
| | 19933 | }, |
| | 19934 | else => |e| return e, |
| | 19935 | }; |
| | 19936 | return try sema.wrapOptional(block, dest_ty, intermediate, inst_src); |
| 19908 | }, | 19937 | }, |
| 19909 | .Pointer => { | 19938 | .Pointer => pointer: { |
| 19910 | const dest_info = dest_ty.ptrInfo().data; | 19939 | const dest_info = dest_ty.ptrInfo().data; |
| 19911 | | 19940 | |
| 19912 | // Function body to function pointer. | 19941 | // Function body to function pointer. |
| ... | @@ -20011,16 +20040,26 @@ fn coerce( | ... | @@ -20011,16 +20040,26 @@ fn coerce( |
| 20011 | return sema.addConstant(dest_ty, Value.@"null"); | 20040 | return sema.addConstant(dest_ty, Value.@"null"); |
| 20012 | }, | 20041 | }, |
| 20013 | .ComptimeInt => { | 20042 | .ComptimeInt => { |
| 20014 | const addr = try sema.coerce(block, Type.usize, inst, inst_src); | 20043 | const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, false) catch |err| switch (err) { |
| 20015 | return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); | 20044 | error.NotCoercible => break :pointer, |
| | 20045 | else => |e| return e, |
| | 20046 | }; |
| | 20047 | return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); |
| 20016 | }, | 20048 | }, |
| 20017 | .Int => { | 20049 | .Int => { |
| 20018 | const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) { | 20050 | const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) { |
| 20019 | .signed => Type.isize, | 20051 | .signed => Type.isize, |
| 20020 | .unsigned => Type.usize, | 20052 | .unsigned => Type.usize, |
| 20021 | }; | 20053 | }; |
| 20022 | const addr = try sema.coerce(block, ptr_size_ty, inst, inst_src); | 20054 | const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, false) catch |err| switch (err) { |
| 20023 | return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); | 20055 | error.NotCoercible => { |
| | 20056 | // Try to give more useful notes |
| | 20057 | in_memory_result = try sema.coerceInMemoryAllowed(block, ptr_size_ty, inst_ty, false, target, dest_ty_src, inst_src); |
| | 20058 | break :pointer; |
| | 20059 | }, |
| | 20060 | else => |e| return e, |
| | 20061 | }; |
| | 20062 | return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); |
| 20024 | }, | 20063 | }, |
| 20025 | .Pointer => p: { | 20064 | .Pointer => p: { |
| 20026 | const inst_info = inst_ty.ptrInfo().data; | 20065 | const inst_info = inst_ty.ptrInfo().data; |
| ... | @@ -20155,6 +20194,7 @@ fn coerce( | ... | @@ -20155,6 +20194,7 @@ fn coerce( |
| 20155 | if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| { | 20194 | if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| { |
| 20156 | // comptime known integer to other number | 20195 | // comptime known integer to other number |
| 20157 | if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) { | 20196 | if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) { |
| | 20197 | if (!report_err) return error.NotCoercible; |
| 20158 | return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) }); | 20198 | return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) }); |
| 20159 | } | 20199 | } |
| 20160 | return try sema.addConstant(dest_ty, val); | 20200 | return try sema.addConstant(dest_ty, val); |
| ... | @@ -20356,6 +20396,8 @@ fn coerce( | ... | @@ -20356,6 +20396,8 @@ fn coerce( |
| 20356 | return sema.addConstUndef(dest_ty); | 20396 | return sema.addConstUndef(dest_ty); |
| 20357 | } | 20397 | } |
| 20358 | | 20398 | |
| | 20399 | if (!report_err) return error.NotCoercible; |
| | 20400 | |
| 20359 | const msg = msg: { | 20401 | 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) }); | 20402 | 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); | 20403 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -20534,8 +20576,10 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -20534,8 +20576,10 @@ const InMemoryCoercionResult = union(enum) { |
| 20534 | cur = pair.child; | 20576 | cur = pair.child; |
| 20535 | }, | 20577 | }, |
| 20536 | .optional_shape => |pair| { | 20578 | .optional_shape => |pair| { |
| 20537 | try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type '{}'", .{ | 20579 | var buf_actual: Type.Payload.ElemType = undefined; |
| 20538 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), | 20580 | var buf_wanted: Type.Payload.ElemType = undefined; |
| | 20581 | try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ |
| | 20582 | pair.actual.optionalChild(&buf_actual).fmt(sema.mod), pair.wanted.optionalChild(&buf_wanted).fmt(sema.mod), |
| 20539 | }); | 20583 | }); |
| 20540 | break; | 20584 | break; |
| 20541 | }, | 20585 | }, |