| ... | ... | @@ -15629,10 +15629,10 @@ fn zirCmpEq( |
| 15629 | 15629 | |
| 15630 | 15630 | // comparing null with optionals |
| 15631 | 15631 | if (lhs_ty_tag == .null and (rhs_ty_tag == .optional or rhs_ty.isCPtr(zcu))) { |
| 15632 | | return sema.analyzeIsNull(block, rhs, op == .neq); |
| 15632 | return sema.analyzeIsNull(block, src, rhs, op == .neq); |
| 15633 | 15633 | } |
| 15634 | 15634 | if (rhs_ty_tag == .null and (lhs_ty_tag == .optional or lhs_ty.isCPtr(zcu))) { |
| 15635 | | return sema.analyzeIsNull(block, lhs, op == .neq); |
| 15635 | return sema.analyzeIsNull(block, src, lhs, op == .neq); |
| 15636 | 15636 | } |
| 15637 | 15637 | |
| 15638 | 15638 | if (lhs_ty_tag == .null or rhs_ty_tag == .null) { |
| ... | ... | @@ -17375,7 +17375,7 @@ fn zirIsNonNull( |
| 17375 | 17375 | const src = block.nodeOffset(inst_data.src_node); |
| 17376 | 17376 | const operand = sema.resolveInst(inst_data.operand); |
| 17377 | 17377 | try sema.checkNullableType(block, src, sema.typeOf(operand)); |
| 17378 | | return sema.analyzeIsNull(block, operand, true); |
| 17378 | return sema.analyzeIsNull(block, src, operand, true); |
| 17379 | 17379 | } |
| 17380 | 17380 | |
| 17381 | 17381 | fn zirIsNonNullPtr( |
| ... | ... | @@ -17394,15 +17394,19 @@ fn zirIsNonNullPtr( |
| 17394 | 17394 | const ptr_ty = sema.typeOf(ptr); |
| 17395 | 17395 | assert(ptr_ty.zigTypeTag(zcu) == .pointer); |
| 17396 | 17396 | const nullable_ty = ptr_ty.childType(zcu); |
| 17397 | |
| 17397 | 17398 | try sema.checkNullableType(block, src, nullable_ty); |
| 17399 | |
| 17400 | if (try sema.resolveIsNullFromType(block, src, nullable_ty)) |is_null| { |
| 17401 | return .fromValue(.makeBool(!is_null)); |
| 17402 | } |
| 17403 | |
| 17398 | 17404 | if (sema.resolveValue(ptr)) |ptr_val| { |
| 17399 | 17405 | if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |nullable_val| { |
| 17400 | | return sema.analyzeIsNull(block, .fromValue(nullable_val), true); |
| 17406 | return sema.analyzeIsNull(block, src, .fromValue(nullable_val), true); |
| 17401 | 17407 | } |
| 17402 | 17408 | } |
| 17403 | | if (nullable_ty.isNullFromType(zcu)) |is_null| { |
| 17404 | | return if (is_null) .bool_false else .bool_true; |
| 17405 | | } |
| 17409 | |
| 17406 | 17410 | return block.addUnOp(.is_non_null_ptr, ptr); |
| 17407 | 17411 | } |
| 17408 | 17412 | |
| ... | ... | @@ -30147,25 +30151,25 @@ fn analyzeSliceLen( |
| 30147 | 30151 | fn analyzeIsNull( |
| 30148 | 30152 | sema: *Sema, |
| 30149 | 30153 | block: *Block, |
| 30154 | src: LazySrcLoc, |
| 30150 | 30155 | operand: Air.Inst.Ref, |
| 30151 | 30156 | invert_logic: bool, |
| 30152 | 30157 | ) CompileError!Air.Inst.Ref { |
| 30153 | 30158 | const pt = sema.pt; |
| 30154 | 30159 | const zcu = pt.zcu; |
| 30155 | | const result_ty: Type = .bool; |
| 30160 | |
| 30161 | if (try sema.resolveIsNullFromType(block, src, sema.typeOf(operand))) |is_null| { |
| 30162 | return .fromValue(.makeBool(is_null != invert_logic)); // XOR |
| 30163 | } |
| 30164 | |
| 30156 | 30165 | if (sema.resolveValue(operand)) |opt_val| { |
| 30157 | 30166 | if (opt_val.isUndef(zcu)) { |
| 30158 | | return pt.undefRef(result_ty); |
| 30167 | return pt.undefRef(.bool); |
| 30159 | 30168 | } |
| 30160 | 30169 | const is_null = opt_val.isNull(zcu); |
| 30161 | | const bool_value = if (invert_logic) !is_null else is_null; |
| 30162 | | return if (bool_value) .bool_true else .bool_false; |
| 30170 | return .fromValue(.makeBool(is_null != invert_logic)); // XOR |
| 30163 | 30171 | } |
| 30164 | 30172 | |
| 30165 | | if (sema.typeOf(operand).isNullFromType(zcu)) |is_null| { |
| 30166 | | const result = is_null != invert_logic; |
| 30167 | | return if (result) .bool_true else .bool_false; |
| 30168 | | } |
| 30169 | 30173 | const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null; |
| 30170 | 30174 | return block.addUnOp(air_tag, operand); |
| 30171 | 30175 | } |
| ... | ... | @@ -30218,6 +30222,35 @@ fn resolveIsNonErrVal( |
| 30218 | 30222 | return null; |
| 30219 | 30223 | } |
| 30220 | 30224 | |
| 30225 | fn resolveIsNullFromType( |
| 30226 | sema: *Sema, |
| 30227 | block: *Block, |
| 30228 | src: LazySrcLoc, |
| 30229 | ty: Type, |
| 30230 | ) CompileError!?bool { |
| 30231 | const zcu = sema.pt.zcu; |
| 30232 | return switch (ty.zigTypeTag(zcu)) { |
| 30233 | else => false, |
| 30234 | .null => true, |
| 30235 | .pointer => switch (ty.ptrSize(zcu)) { |
| 30236 | .c => null, |
| 30237 | else => false, |
| 30238 | }, |
| 30239 | .optional => { |
| 30240 | const payload_ty = ty.optionalChild(zcu); |
| 30241 | if (payload_ty.classify(zcu) == .no_possible_value) { |
| 30242 | return true; // e.g. `?noreturn` |
| 30243 | } |
| 30244 | if (payload_ty.zigTypeTag(zcu) == .error_set and |
| 30245 | try sema.resolveErrSetIsEmpty(block, src, payload_ty)) |
| 30246 | { |
| 30247 | return true; // e.g. `?error{}` |
| 30248 | } |
| 30249 | return null; |
| 30250 | }, |
| 30251 | }; |
| 30252 | } |
| 30253 | |
| 30221 | 30254 | fn resolveIsNonErrFromType( |
| 30222 | 30255 | sema: *Sema, |
| 30223 | 30256 | block: *Block, |
| ... | ... | @@ -30226,7 +30259,6 @@ fn resolveIsNonErrFromType( |
| 30226 | 30259 | ) CompileError!?Value { |
| 30227 | 30260 | const pt = sema.pt; |
| 30228 | 30261 | const zcu = pt.zcu; |
| 30229 | | const ip = &zcu.intern_pool; |
| 30230 | 30262 | const ot = operand_ty.zigTypeTag(zcu); |
| 30231 | 30263 | if (ot != .error_set and ot != .error_union) return .true; |
| 30232 | 30264 | if (ot == .error_set) return .false; |
| ... | ... | @@ -30236,29 +30268,54 @@ fn resolveIsNonErrFromType( |
| 30236 | 30268 | if (payload_ty.classify(zcu) == .no_possible_value) { |
| 30237 | 30269 | return .false; |
| 30238 | 30270 | } |
| 30271 | if (try sema.resolveErrSetIsEmpty(block, src, operand_ty.errorUnionSet(zcu))) { |
| 30272 | return .true; |
| 30273 | } |
| 30274 | return null; |
| 30275 | } |
| 30239 | 30276 | |
| 30240 | | // exception if the error union error set is known to be empty, |
| 30241 | | // we allow the comparison but always make it comptime-known. |
| 30242 | | return err_set: switch (ip.errorUnionSet(operand_ty.toIntern())) { |
| 30243 | | .anyerror_type => null, |
| 30277 | /// Returns `true` iff the error set type `orig_err_set_ty` contains no errors. |
| 30278 | /// |
| 30279 | /// This is used to give comptime answers for whether `error{}!T` is an error or a payload, as well |
| 30280 | /// as whether `?error{}` is null. The type `error{}` cannot be NPV, as it has runtime bits, but the |
| 30281 | /// only value of that type which can exist is `undefined`; semantically it has no "legal" value. |
| 30282 | /// TODO: this runs into some unsolved language design questions about such types. Performing a |
| 30283 | /// coercion from `@as(E, undefined)` to `E!T` needs to semantically result in an `undefined` error |
| 30284 | /// union if our implementation is to be legal, and likewise for coercing `@as(E, undefined)` to |
| 30285 | /// `?E` (for an error set `E`) because our implementation uses the zero error value at runtime to |
| 30286 | /// represent `null`. The unsolved problem is the exact rules for `undefined` propagation through |
| 30287 | /// these types: for instance, what if `@as(u32, undfined)` is coerced to `?u32`? What about error |
| 30288 | /// union *payloads*, i.e. `@as(u32, undefined)` to `E!u32`? That one is analagous to the optional |
| 30289 | /// example in some ways, but right now I believe there is code which relies on that coercion giving |
| 30290 | /// a well-defined error union with an `undefined` payload. |
| 30291 | /// Relevant issues/discussions: |
| 30292 | /// * https://github.com/ziglang/zig/issues/1831 |
| 30293 | /// * https://github.com/ziglang/zig/issues/6762 |
| 30294 | /// * https://github.com/ziglang/zig/issues/1831#issuecomment-722129239 |
| 30295 | fn resolveErrSetIsEmpty( |
| 30296 | sema: *Sema, |
| 30297 | block: *Block, |
| 30298 | src: LazySrcLoc, |
| 30299 | orig_err_set_ty: Type, |
| 30300 | ) CompileError!bool { |
| 30301 | const ip = &sema.pt.zcu.intern_pool; |
| 30302 | err_set: switch (orig_err_set_ty.toIntern()) { |
| 30303 | .anyerror_type => return false, |
| 30244 | 30304 | .adhoc_inferred_error_set_type => { |
| 30245 | 30305 | // This is *our* error set; that is, we're currently analyzing the function |
| 30246 | 30306 | // which owns it. Trying to resolve it now would cause a dependency loop. |
| 30247 | 30307 | // Instead, accept that we don't know. |
| 30248 | | return null; |
| 30308 | return false; |
| 30249 | 30309 | }, |
| 30250 | | else => |set_ty| switch (ip.indexToKey(set_ty)) { |
| 30251 | | .error_set_type => |error_set_type| switch (error_set_type.names.len) { |
| 30252 | | 0 => .true, |
| 30253 | | else => null, |
| 30254 | | }, |
| 30310 | else => |err_set_ty| switch (ip.indexToKey(err_set_ty)) { |
| 30311 | .error_set_type => |es| return es.names.len == 0, |
| 30255 | 30312 | .inferred_error_set_type => |func_index| { |
| 30256 | 30313 | if (sema.fn_ret_ty_ies) |ies| { |
| 30257 | 30314 | if (ies.func == func_index) { |
| 30258 | 30315 | // This is *our* error set; that is, we're currently analyzing the function |
| 30259 | 30316 | // which owns it. Trying to resolve it now would cause a dependency loop. |
| 30260 | 30317 | // Instead, accept that we don't know. |
| 30261 | | return null; |
| 30318 | return false; |
| 30262 | 30319 | } |
| 30263 | 30320 | } |
| 30264 | 30321 | try sema.ensureFuncIesResolved(block, src, func_index); |
| ... | ... | @@ -30266,7 +30323,7 @@ fn resolveIsNonErrFromType( |
| 30266 | 30323 | }, |
| 30267 | 30324 | else => unreachable, |
| 30268 | 30325 | }, |
| 30269 | | }; |
| 30326 | } |
| 30270 | 30327 | } |
| 30271 | 30328 | |
| 30272 | 30329 | fn analyzeIsNonErr( |
| ... | ... | @@ -30732,7 +30789,7 @@ fn analyzeSlice( |
| 30732 | 30789 | if (block.wantSafety()) { |
| 30733 | 30790 | // requirement: slicing C ptr is non-null |
| 30734 | 30791 | if (ptr_ptr_child_ty.isCPtr(zcu)) { |
| 30735 | | const is_non_null = try sema.analyzeIsNull(block, ptr, true); |
| 30792 | const is_non_null = try block.addUnOp(.is_non_null, ptr); |
| 30736 | 30793 | try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null); |
| 30737 | 30794 | } |
| 30738 | 30795 | |
| ... | ... | @@ -30792,7 +30849,7 @@ fn analyzeSlice( |
| 30792 | 30849 | if (block.wantSafety()) { |
| 30793 | 30850 | // requirement: slicing C ptr is non-null |
| 30794 | 30851 | if (ptr_ptr_child_ty.isCPtr(zcu)) { |
| 30795 | | const is_non_null = try sema.analyzeIsNull(block, ptr, true); |
| 30852 | const is_non_null = try block.addUnOp(.is_non_null, ptr); |
| 30796 | 30853 | try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null); |
| 30797 | 30854 | } |
| 30798 | 30855 | |