| author | |
| committer | |
| log | 4a76523b92bcf0e9b48438cb22f49e67e0ab3fa1 |
| tree | d8a05453ecd23c9e1dbbc912731958e3b84c9c7a |
| parent | 372e9709ad2f4af24461f0fa601754a469091c2b |
| parent | c1508c98f479497c2b2586ea944be9f3ddae28fc |
| signature |
Field elem access12 files changed, 523 insertions(+), 311 deletions(-)
src/Air.zig+8| ... | ... | @@ -367,6 +367,12 @@ pub const Inst = struct { |
| 367 | 367 | /// Given a slice value, return the pointer. |
| 368 | 368 | /// Uses the `ty_op` field. |
| 369 | 369 | slice_ptr, |
| 370 | /// Given a pointer to a slice, return a pointer to the length of the slice. | |
| 371 | /// Uses the `ty_op` field. | |
| 372 | ptr_slice_len_ptr, | |
| 373 | /// Given a pointer to a slice, return a pointer to the pointer of the slice. | |
| 374 | /// Uses the `ty_op` field. | |
| 375 | ptr_slice_ptr_ptr, | |
| 370 | 376 | /// Given an array value and element index, return the element value at that index. |
| 371 | 377 | /// Result type is the element type of the array operand. |
| 372 | 378 | /// Uses the `bin_op` field. |
| ... | ... | @@ -707,6 +713,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 707 | 713 | .wrap_errunion_payload, |
| 708 | 714 | .wrap_errunion_err, |
| 709 | 715 | .slice_ptr, |
| 716 | .ptr_slice_len_ptr, | |
| 717 | .ptr_slice_ptr_ptr, | |
| 710 | 718 | .struct_field_ptr_index_0, |
| 711 | 719 | .struct_field_ptr_index_1, |
| 712 | 720 | .struct_field_ptr_index_2, |
src/AstGen.zig+16-21| ... | ... | @@ -193,9 +193,6 @@ pub const ResultLoc = union(enum) { |
| 193 | 193 | /// The expression must generate a pointer rather than a value. For example, the left hand side |
| 194 | 194 | /// of an assignment uses this kind of result location. |
| 195 | 195 | ref, |
| 196 | /// The callee will accept a ref, but it is not necessary, and the `ResultLoc` | |
| 197 | /// may be treated as `none` instead. | |
| 198 | none_or_ref, | |
| 199 | 196 | /// The expression will be coerced into this type, but it will be evaluated as an rvalue. |
| 200 | 197 | ty: Zir.Inst.Ref, |
| 201 | 198 | /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion, |
| ... | ... | @@ -231,7 +228,7 @@ pub const ResultLoc = union(enum) { |
| 231 | 228 | fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy { |
| 232 | 229 | switch (rl) { |
| 233 | 230 | // In this branch there will not be any store_to_block_ptr instructions. |
| 234 | .discard, .none, .none_or_ref, .ty, .coerced_ty, .ref => return .{ | |
| 231 | .discard, .none, .ty, .coerced_ty, .ref => return .{ | |
| 235 | 232 | .tag = .break_operand, |
| 236 | 233 | .elide_store_to_block_ptr_instructions = false, |
| 237 | 234 | }, |
| ... | ... | @@ -727,7 +724,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 727 | 724 | .start = start, |
| 728 | 725 | }); |
| 729 | 726 | switch (rl) { |
| 730 | .ref, .none_or_ref => return result, | |
| 727 | .ref => return result, | |
| 731 | 728 | else => { |
| 732 | 729 | const dereffed = try gz.addUnNode(.load, result, node); |
| 733 | 730 | return rvalue(gz, rl, dereffed, node); |
| ... | ... | @@ -745,7 +742,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 745 | 742 | .end = end, |
| 746 | 743 | }); |
| 747 | 744 | switch (rl) { |
| 748 | .ref, .none_or_ref => return result, | |
| 745 | .ref => return result, | |
| 749 | 746 | else => { |
| 750 | 747 | const dereffed = try gz.addUnNode(.load, result, node); |
| 751 | 748 | return rvalue(gz, rl, dereffed, node); |
| ... | ... | @@ -765,7 +762,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 765 | 762 | .sentinel = sentinel, |
| 766 | 763 | }); |
| 767 | 764 | switch (rl) { |
| 768 | .ref, .none_or_ref => return result, | |
| 765 | .ref => return result, | |
| 769 | 766 | else => { |
| 770 | 767 | const dereffed = try gz.addUnNode(.load, result, node); |
| 771 | 768 | return rvalue(gz, rl, dereffed, node); |
| ... | ... | @@ -776,7 +773,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 776 | 773 | .deref => { |
| 777 | 774 | const lhs = try expr(gz, scope, .none, node_datas[node].lhs); |
| 778 | 775 | switch (rl) { |
| 779 | .ref, .none_or_ref => return lhs, | |
| 776 | .ref => return lhs, | |
| 780 | 777 | else => { |
| 781 | 778 | const result = try gz.addUnNode(.load, lhs, node); |
| 782 | 779 | return rvalue(gz, rl, result, node); |
| ... | ... | @@ -1273,7 +1270,7 @@ fn arrayInitExpr( |
| 1273 | 1270 | return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref); |
| 1274 | 1271 | } |
| 1275 | 1272 | }, |
| 1276 | .none, .none_or_ref => { | |
| 1273 | .none => { | |
| 1277 | 1274 | if (types.array != .none) { |
| 1278 | 1275 | return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init); |
| 1279 | 1276 | } else { |
| ... | ... | @@ -1475,7 +1472,7 @@ fn structInitExpr( |
| 1475 | 1472 | return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref); |
| 1476 | 1473 | } |
| 1477 | 1474 | }, |
| 1478 | .none, .none_or_ref => { | |
| 1475 | .none => { | |
| 1479 | 1476 | if (struct_init.ast.type_expr != 0) { |
| 1480 | 1477 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1481 | 1478 | return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); |
| ... | ... | @@ -5133,7 +5130,7 @@ fn fieldAccess( |
| 5133 | 5130 | if (rl == .ref) { |
| 5134 | 5131 | return addFieldAccess(.field_ptr, gz, scope, .ref, node); |
| 5135 | 5132 | } else { |
| 5136 | const access = try addFieldAccess(.field_val, gz, scope, .none_or_ref, node); | |
| 5133 | const access = try addFieldAccess(.field_val, gz, scope, .none, node); | |
| 5137 | 5134 | return rvalue(gz, rl, access, node); |
| 5138 | 5135 | } |
| 5139 | 5136 | } |
| ... | ... | @@ -5178,7 +5175,7 @@ fn arrayAccess( |
| 5178 | 5175 | ), |
| 5179 | 5176 | else => return rvalue(gz, rl, try gz.addBin( |
| 5180 | 5177 | .elem_val, |
| 5181 | try expr(gz, scope, .none_or_ref, node_datas[node].lhs), | |
| 5178 | try expr(gz, scope, .none, node_datas[node].lhs), | |
| 5182 | 5179 | try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), |
| 5183 | 5180 | ), node), |
| 5184 | 5181 | } |
| ... | ... | @@ -6664,7 +6661,7 @@ fn identifier( |
| 6664 | 6661 | ); |
| 6665 | 6662 | |
| 6666 | 6663 | switch (rl) { |
| 6667 | .ref, .none_or_ref => return ptr_inst, | |
| 6664 | .ref => return ptr_inst, | |
| 6668 | 6665 | else => { |
| 6669 | 6666 | const loaded = try gz.addUnNode(.load, ptr_inst, ident); |
| 6670 | 6667 | return rvalue(gz, rl, loaded, ident); |
| ... | ... | @@ -6700,7 +6697,7 @@ fn identifier( |
| 6700 | 6697 | // Decl references happen by name rather than ZIR index so that when unrelated |
| 6701 | 6698 | // decls are modified, ZIR code containing references to them can be unmodified. |
| 6702 | 6699 | switch (rl) { |
| 6703 | .ref, .none_or_ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token), | |
| 6700 | .ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token), | |
| 6704 | 6701 | else => { |
| 6705 | 6702 | const result = try gz.addStrTok(.decl_val, name_str_index, ident_token); |
| 6706 | 6703 | return rvalue(gz, rl, result, ident); |
| ... | ... | @@ -7105,7 +7102,7 @@ fn as( |
| 7105 | 7102 | ) InnerError!Zir.Inst.Ref { |
| 7106 | 7103 | const dest_type = try typeExpr(gz, scope, lhs); |
| 7107 | 7104 | switch (rl) { |
| 7108 | .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty => { | |
| 7105 | .none, .discard, .ref, .ty, .coerced_ty => { | |
| 7109 | 7106 | const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node); |
| 7110 | 7107 | return rvalue(gz, rl, result, node); |
| 7111 | 7108 | }, |
| ... | ... | @@ -7128,7 +7125,7 @@ fn unionInit( |
| 7128 | 7125 | const union_type = try typeExpr(gz, scope, params[0]); |
| 7129 | 7126 | const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); |
| 7130 | 7127 | switch (rl) { |
| 7131 | .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => { | |
| 7128 | .none, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => { | |
| 7132 | 7129 | _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{ |
| 7133 | 7130 | .container_type = union_type, |
| 7134 | 7131 | .field_name = field_name, |
| ... | ... | @@ -7192,7 +7189,7 @@ fn bitCast( |
| 7192 | 7189 | const astgen = gz.astgen; |
| 7193 | 7190 | const dest_type = try typeExpr(gz, scope, lhs); |
| 7194 | 7191 | switch (rl) { |
| 7195 | .none, .none_or_ref, .discard, .ty, .coerced_ty => { | |
| 7192 | .none, .discard, .ty, .coerced_ty => { | |
| 7196 | 7193 | const operand = try expr(gz, scope, .none, rhs); |
| 7197 | 7194 | const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{ |
| 7198 | 7195 | .lhs = dest_type, |
| ... | ... | @@ -8799,7 +8796,7 @@ fn rvalue( |
| 8799 | 8796 | ) InnerError!Zir.Inst.Ref { |
| 8800 | 8797 | if (gz.endsWithNoReturn()) return result; |
| 8801 | 8798 | switch (rl) { |
| 8802 | .none, .none_or_ref, .coerced_ty => return result, | |
| 8799 | .none, .coerced_ty => return result, | |
| 8803 | 8800 | .discard => { |
| 8804 | 8801 | // Emit a compile error for discarding error values. |
| 8805 | 8802 | _ = try gz.addUnNode(.ensure_result_non_error, result, src_node); |
| ... | ... | @@ -9561,9 +9558,7 @@ const GenZir = struct { |
| 9561 | 9558 | gz.rl_ty_inst = ty_inst; |
| 9562 | 9559 | gz.break_result_loc = parent_rl; |
| 9563 | 9560 | }, |
| 9564 | .none_or_ref => { | |
| 9565 | gz.break_result_loc = .ref; | |
| 9566 | }, | |
| 9561 | ||
| 9567 | 9562 | .discard, .none, .ptr, .ref => { |
| 9568 | 9563 | gz.break_result_loc = parent_rl; |
| 9569 | 9564 | }, |
src/Liveness.zig+2| ... | ... | @@ -300,6 +300,8 @@ fn analyzeInst( |
| 300 | 300 | .wrap_errunion_err, |
| 301 | 301 | .slice_ptr, |
| 302 | 302 | .slice_len, |
| 303 | .ptr_slice_len_ptr, | |
| 304 | .ptr_slice_ptr_ptr, | |
| 303 | 305 | .struct_field_ptr_index_0, |
| 304 | 306 | .struct_field_ptr_index_1, |
| 305 | 307 | .struct_field_ptr_index_2, |
src/Sema.zig+291-234| ... | ... | @@ -300,7 +300,7 @@ pub const Block = struct { |
| 300 | 300 | .ty = ty, |
| 301 | 301 | .payload = try block.sema.addExtra(Air.StructField{ |
| 302 | 302 | .struct_operand = struct_ptr, |
| 303 | .field_index = @intCast(u32, field_index), | |
| 303 | .field_index = field_index, | |
| 304 | 304 | }), |
| 305 | 305 | } }, |
| 306 | 306 | }); |
| ... | ... | @@ -315,6 +315,24 @@ pub const Block = struct { |
| 315 | 315 | }); |
| 316 | 316 | } |
| 317 | 317 | |
| 318 | pub fn addStructFieldVal( | |
| 319 | block: *Block, | |
| 320 | struct_val: Air.Inst.Ref, | |
| 321 | field_index: u32, | |
| 322 | field_ty: Type, | |
| 323 | ) !Air.Inst.Ref { | |
| 324 | return block.addInst(.{ | |
| 325 | .tag = .struct_field_val, | |
| 326 | .data = .{ .ty_pl = .{ | |
| 327 | .ty = try block.sema.addType(field_ty), | |
| 328 | .payload = try block.sema.addExtra(Air.StructField{ | |
| 329 | .struct_operand = struct_val, | |
| 330 | .field_index = field_index, | |
| 331 | }), | |
| 332 | } }, | |
| 333 | }); | |
| 334 | } | |
| 335 | ||
| 318 | 336 | pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref { |
| 319 | 337 | return Air.indexToRef(try block.addInstAsIndex(inst)); |
| 320 | 338 | } |
| ... | ... | @@ -1968,44 +1986,38 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1968 | 1986 | |
| 1969 | 1987 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 1970 | 1988 | const src = inst_data.src(); |
| 1971 | const array = sema.resolveInst(inst_data.operand); | |
| 1972 | const array_ty = sema.typeOf(array); | |
| 1989 | const object = sema.resolveInst(inst_data.operand); | |
| 1990 | const object_ty = sema.typeOf(object); | |
| 1973 | 1991 | |
| 1974 | if (array_ty.isSlice()) { | |
| 1975 | return sema.analyzeSliceLen(block, src, array); | |
| 1976 | } | |
| 1992 | const is_pointer_to = object_ty.isSinglePointer(); | |
| 1977 | 1993 | |
| 1978 | if (array_ty.isSinglePointer()) { | |
| 1979 | const elem_ty = array_ty.elemType(); | |
| 1980 | if (elem_ty.isSlice()) { | |
| 1981 | const slice_inst = try sema.analyzeLoad(block, src, array, src); | |
| 1982 | return sema.analyzeSliceLen(block, src, slice_inst); | |
| 1983 | } | |
| 1984 | if (!elem_ty.isIndexable()) { | |
| 1985 | const msg = msg: { | |
| 1986 | const msg = try sema.errMsg( | |
| 1987 | block, | |
| 1988 | src, | |
| 1989 | "type '{}' does not support indexing", | |
| 1990 | .{elem_ty}, | |
| 1991 | ); | |
| 1992 | errdefer msg.destroy(sema.gpa); | |
| 1993 | try sema.errNote( | |
| 1994 | block, | |
| 1995 | src, | |
| 1996 | msg, | |
| 1997 | "for loop operand must be an array, slice, tuple, or vector", | |
| 1998 | .{}, | |
| 1999 | ); | |
| 2000 | break :msg msg; | |
| 2001 | }; | |
| 2002 | return sema.failWithOwnedErrorMsg(msg); | |
| 2003 | } | |
| 2004 | const result_ptr = try sema.fieldPtr(block, src, array, "len", src); | |
| 2005 | return sema.analyzeLoad(block, src, result_ptr, src); | |
| 1994 | const array_ty = if (is_pointer_to) | |
| 1995 | object_ty.childType() | |
| 1996 | else | |
| 1997 | object_ty; | |
| 1998 | ||
| 1999 | if (!array_ty.isIndexable()) { | |
| 2000 | const msg = msg: { | |
| 2001 | const msg = try sema.errMsg( | |
| 2002 | block, | |
| 2003 | src, | |
| 2004 | "type '{}' does not support indexing", | |
| 2005 | .{array_ty}, | |
| 2006 | ); | |
| 2007 | errdefer msg.destroy(sema.gpa); | |
| 2008 | try sema.errNote( | |
| 2009 | block, | |
| 2010 | src, | |
| 2011 | msg, | |
| 2012 | "for loop operand must be an array, slice, tuple, or vector", | |
| 2013 | .{}, | |
| 2014 | ); | |
| 2015 | break :msg msg; | |
| 2016 | }; | |
| 2017 | return sema.failWithOwnedErrorMsg(msg); | |
| 2006 | 2018 | } |
| 2007 | 2019 | |
| 2008 | return sema.fail(block, src, "TODO implement Sema.zirIndexablePtrLen", .{}); | |
| 2020 | return sema.fieldVal(block, src, object, "len", src); | |
| 2009 | 2021 | } |
| 2010 | 2022 | |
| 2011 | 2023 | fn zirAllocExtended( |
| ... | ... | @@ -2304,7 +2316,7 @@ fn validateStructInit( |
| 2304 | 2316 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; |
| 2305 | 2317 | const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); |
| 2306 | 2318 | const field_index = struct_obj.fields.getIndex(field_name) orelse |
| 2307 | return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name); | |
| 2319 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | |
| 2308 | 2320 | if (found_fields[field_index] != 0) { |
| 2309 | 2321 | const other_field_ptr = found_fields[field_index]; |
| 2310 | 2322 | const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node; |
| ... | ... | @@ -2366,7 +2378,32 @@ fn zirValidateArrayInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil |
| 2366 | 2378 | } |
| 2367 | 2379 | } |
| 2368 | 2380 | |
| 2369 | fn failWithBadFieldAccess( | |
| 2381 | fn failWithBadMemberAccess( | |
| 2382 | sema: *Sema, | |
| 2383 | block: *Block, | |
| 2384 | agg_ty: Type, | |
| 2385 | field_src: LazySrcLoc, | |
| 2386 | field_name: []const u8, | |
| 2387 | ) CompileError { | |
| 2388 | const kw_name = switch (agg_ty.zigTypeTag()) { | |
| 2389 | .Union => "union", | |
| 2390 | .Struct => "struct", | |
| 2391 | .Opaque => "opaque", | |
| 2392 | .Enum => "enum", | |
| 2393 | else => unreachable, | |
| 2394 | }; | |
| 2395 | const msg = msg: { | |
| 2396 | const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{s}'", .{ | |
| 2397 | kw_name, agg_ty, field_name, | |
| 2398 | }); | |
| 2399 | errdefer msg.destroy(sema.gpa); | |
| 2400 | try sema.addDeclaredHereNote(msg, agg_ty); | |
| 2401 | break :msg msg; | |
| 2402 | }; | |
| 2403 | return sema.failWithOwnedErrorMsg(msg); | |
| 2404 | } | |
| 2405 | ||
| 2406 | fn failWithBadStructFieldAccess( | |
| 2370 | 2407 | sema: *Sema, |
| 2371 | 2408 | block: *Block, |
| 2372 | 2409 | struct_obj: *Module.Struct, |
| ... | ... | @@ -5119,16 +5156,10 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 5119 | 5156 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 5120 | 5157 | const src = inst_data.src(); |
| 5121 | 5158 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; |
| 5122 | const lhs_src: LazySrcLoc = src; // TODO | |
| 5123 | 5159 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; |
| 5124 | 5160 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); |
| 5125 | 5161 | const object = sema.resolveInst(extra.lhs); |
| 5126 | if (sema.typeOf(object).isSinglePointer()) { | |
| 5127 | const result_ptr = try sema.fieldPtr(block, src, object, field_name, field_name_src); | |
| 5128 | return sema.analyzeLoad(block, src, result_ptr, lhs_src); | |
| 5129 | } else { | |
| 5130 | return sema.fieldVal(block, src, object, field_name, field_name_src); | |
| 5131 | } | |
| 5162 | return sema.fieldVal(block, src, object, field_name, field_name_src); | |
| 5132 | 5163 | } |
| 5133 | 5164 | |
| 5134 | 5165 | fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -8822,7 +8853,7 @@ fn zirStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) |
| 8822 | 8853 | const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; |
| 8823 | 8854 | const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); |
| 8824 | 8855 | const field_index = struct_obj.fields.getIndex(field_name) orelse |
| 8825 | return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name); | |
| 8856 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | |
| 8826 | 8857 | if (found_fields[field_index] != 0) { |
| 8827 | 8858 | const other_field_type = found_fields[field_index]; |
| 8828 | 8859 | const other_field_type_data = zir_datas[other_field_type].pl_node; |
| ... | ... | @@ -9031,7 +9062,7 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 9031 | 9062 | .Struct => { |
| 9032 | 9063 | const struct_obj = resolved_ty.castTag(.@"struct").?.data; |
| 9033 | 9064 | const field = struct_obj.fields.get(field_name) orelse |
| 9034 | return sema.failWithBadFieldAccess(block, struct_obj, src, field_name); | |
| 9065 | return sema.failWithBadStructFieldAccess(block, struct_obj, src, field_name); | |
| 9035 | 9066 | return sema.addType(field.ty); |
| 9036 | 9067 | }, |
| 9037 | 9068 | .Union => { |
| ... | ... | @@ -9331,7 +9362,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 9331 | 9362 | const dest_info = dest_ty.intInfo(target); |
| 9332 | 9363 | |
| 9333 | 9364 | if (src_info.bits == 0 or dest_info.bits == 0) { |
| 9334 | return sema.addConstant(dest_ty, Value.initTag(.zero)); | |
| 9365 | return sema.addConstant(dest_ty, Value.zero); | |
| 9335 | 9366 | } |
| 9336 | 9367 | |
| 9337 | 9368 | if (!src_is_comptime_int) { |
| ... | ... | @@ -10688,12 +10719,22 @@ fn fieldVal( |
| 10688 | 10719 | const object_src = src; // TODO better source location |
| 10689 | 10720 | const object_ty = sema.typeOf(object); |
| 10690 | 10721 | |
| 10691 | switch (object_ty.zigTypeTag()) { | |
| 10722 | // Zig allows dereferencing a single pointer during field lookup. Note that | |
| 10723 | // we don't actually need to generate the dereference some field lookups, like the | |
| 10724 | // length of arrays and other comptime operations. | |
| 10725 | const is_pointer_to = object_ty.isSinglePointer(); | |
| 10726 | ||
| 10727 | const inner_ty = if (is_pointer_to) | |
| 10728 | object_ty.childType() | |
| 10729 | else | |
| 10730 | object_ty; | |
| 10731 | ||
| 10732 | switch (inner_ty.zigTypeTag()) { | |
| 10692 | 10733 | .Array => { |
| 10693 | 10734 | if (mem.eql(u8, field_name, "len")) { |
| 10694 | 10735 | return sema.addConstant( |
| 10695 | 10736 | Type.initTag(.comptime_int), |
| 10696 | try Value.Tag.int_u64.create(arena, object_ty.arrayLen()), | |
| 10737 | try Value.Tag.int_u64.create(arena, inner_ty.arrayLen()), | |
| 10697 | 10738 | ); |
| 10698 | 10739 | } else { |
| 10699 | 10740 | return sema.fail( |
| ... | ... | @@ -10704,75 +10745,60 @@ fn fieldVal( |
| 10704 | 10745 | ); |
| 10705 | 10746 | } |
| 10706 | 10747 | }, |
| 10707 | .Pointer => switch (object_ty.ptrSize()) { | |
| 10708 | .Slice => { | |
| 10709 | if (mem.eql(u8, field_name, "ptr")) { | |
| 10710 | const buf = try arena.create(Type.SlicePtrFieldTypeBuffer); | |
| 10711 | const result_ty = object_ty.slicePtrFieldType(buf); | |
| 10712 | if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| { | |
| 10713 | if (val.isUndef()) return sema.addConstUndef(result_ty); | |
| 10714 | return sema.addConstant(result_ty, val.slicePtr()); | |
| 10715 | } | |
| 10716 | try sema.requireRuntimeBlock(block, src); | |
| 10717 | return block.addTyOp(.slice_ptr, result_ty, object); | |
| 10718 | } else if (mem.eql(u8, field_name, "len")) { | |
| 10719 | const result_ty = Type.usize; | |
| 10720 | if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| { | |
| 10721 | if (val.isUndef()) return sema.addConstUndef(result_ty); | |
| 10722 | return sema.addConstant( | |
| 10723 | result_ty, | |
| 10724 | try Value.Tag.int_u64.create(arena, val.sliceLen()), | |
| 10725 | ); | |
| 10726 | } | |
| 10727 | try sema.requireRuntimeBlock(block, src); | |
| 10728 | return block.addTyOp(.slice_len, result_ty, object); | |
| 10729 | } else { | |
| 10730 | return sema.fail( | |
| 10731 | block, | |
| 10732 | field_name_src, | |
| 10733 | "no member named '{s}' in '{}'", | |
| 10734 | .{ field_name, object_ty }, | |
| 10735 | ); | |
| 10748 | .Pointer => if (inner_ty.isSlice()) { | |
| 10749 | if (mem.eql(u8, field_name, "ptr")) { | |
| 10750 | const slice = if (is_pointer_to) | |
| 10751 | try sema.analyzeLoad(block, src, object, object_src) | |
| 10752 | else | |
| 10753 | object; | |
| 10754 | ||
| 10755 | const buf = try arena.create(Type.SlicePtrFieldTypeBuffer); | |
| 10756 | const result_ty = inner_ty.slicePtrFieldType(buf); | |
| 10757 | ||
| 10758 | if (try sema.resolveMaybeUndefVal(block, object_src, slice)) |val| { | |
| 10759 | if (val.isUndef()) return sema.addConstUndef(result_ty); | |
| 10760 | return sema.addConstant(result_ty, val.slicePtr()); | |
| 10736 | 10761 | } |
| 10737 | }, | |
| 10738 | .One => { | |
| 10739 | const ptr_child = object_ty.elemType(); | |
| 10740 | switch (ptr_child.zigTypeTag()) { | |
| 10741 | .Array => { | |
| 10742 | if (mem.eql(u8, field_name, "len")) { | |
| 10743 | return sema.addConstant( | |
| 10744 | Type.initTag(.comptime_int), | |
| 10745 | try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()), | |
| 10746 | ); | |
| 10747 | } else { | |
| 10748 | return sema.fail( | |
| 10749 | block, | |
| 10750 | field_name_src, | |
| 10751 | "no member named '{s}' in '{}'", | |
| 10752 | .{ field_name, object_ty }, | |
| 10753 | ); | |
| 10754 | } | |
| 10755 | }, | |
| 10756 | .Struct => { | |
| 10757 | const struct_ptr_deref = try sema.analyzeLoad(block, src, object, object_src); | |
| 10758 | return sema.unionFieldVal(block, src, struct_ptr_deref, field_name, field_name_src, ptr_child); | |
| 10759 | }, | |
| 10760 | .Union => { | |
| 10761 | const union_ptr_deref = try sema.analyzeLoad(block, src, object, object_src); | |
| 10762 | return sema.unionFieldVal(block, src, union_ptr_deref, field_name, field_name_src, ptr_child); | |
| 10763 | }, | |
| 10764 | else => {}, | |
| 10762 | try sema.requireRuntimeBlock(block, src); | |
| 10763 | return block.addTyOp(.slice_ptr, result_ty, slice); | |
| 10764 | } else if (mem.eql(u8, field_name, "len")) { | |
| 10765 | const slice = if (is_pointer_to) | |
| 10766 | try sema.analyzeLoad(block, src, object, object_src) | |
| 10767 | else | |
| 10768 | object; | |
| 10769 | ||
| 10770 | const result_ty = Type.usize; | |
| 10771 | ||
| 10772 | if (try sema.resolveMaybeUndefVal(block, object_src, slice)) |val| { | |
| 10773 | if (val.isUndef()) return sema.addConstUndef(result_ty); | |
| 10774 | return sema.addConstant( | |
| 10775 | result_ty, | |
| 10776 | try Value.Tag.int_u64.create(arena, val.sliceLen()), | |
| 10777 | ); | |
| 10765 | 10778 | } |
| 10766 | }, | |
| 10767 | .Many, .C => {}, | |
| 10779 | try sema.requireRuntimeBlock(block, src); | |
| 10780 | return block.addTyOp(.slice_len, result_ty, slice); | |
| 10781 | } else { | |
| 10782 | return sema.fail( | |
| 10783 | block, | |
| 10784 | field_name_src, | |
| 10785 | "no member named '{s}' in '{}'", | |
| 10786 | .{ field_name, object_ty }, | |
| 10787 | ); | |
| 10788 | } | |
| 10768 | 10789 | }, |
| 10769 | 10790 | .Type => { |
| 10770 | const val = (try sema.resolveDefinedValue(block, object_src, object)).?; | |
| 10791 | const dereffed_type = if (is_pointer_to) | |
| 10792 | try sema.analyzeLoad(block, src, object, object_src) | |
| 10793 | else | |
| 10794 | object; | |
| 10795 | ||
| 10796 | const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?; | |
| 10771 | 10797 | var to_type_buffer: Value.ToTypeBuffer = undefined; |
| 10772 | 10798 | const child_type = val.toType(&to_type_buffer); |
| 10799 | ||
| 10773 | 10800 | switch (child_type.zigTypeTag()) { |
| 10774 | 10801 | .ErrorSet => { |
| 10775 | // TODO resolve inferred error sets | |
| 10776 | 10802 | const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: { |
| 10777 | 10803 | const error_set = payload.data; |
| 10778 | 10804 | // TODO this is O(N). I'm putting off solving this until we solve inferred |
| ... | ... | @@ -10842,8 +10868,20 @@ fn fieldVal( |
| 10842 | 10868 | else => return sema.fail(block, src, "type '{}' has no members", .{child_type}), |
| 10843 | 10869 | } |
| 10844 | 10870 | }, |
| 10845 | .Struct => return sema.structFieldVal(block, src, object, field_name, field_name_src, object_ty), | |
| 10846 | .Union => return sema.unionFieldVal(block, src, object, field_name, field_name_src, object_ty), | |
| 10871 | .Struct => if (is_pointer_to) { | |
| 10872 | // Avoid loading the entire struct by fetching a pointer and loading that | |
| 10873 | const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty); | |
| 10874 | return sema.analyzeLoad(block, src, field_ptr, object_src); | |
| 10875 | } else { | |
| 10876 | return sema.structFieldVal(block, src, object, field_name, field_name_src, inner_ty); | |
| 10877 | }, | |
| 10878 | .Union => if (is_pointer_to) { | |
| 10879 | // Avoid loading the entire union by fetching a pointer and loading that | |
| 10880 | const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty); | |
| 10881 | return sema.analyzeLoad(block, src, field_ptr, object_src); | |
| 10882 | } else { | |
| 10883 | return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty); | |
| 10884 | }, | |
| 10847 | 10885 | else => {}, |
| 10848 | 10886 | } |
| 10849 | 10887 | return sema.fail(block, src, "type '{}' does not support field access", .{object_ty}); |
| ... | ... | @@ -10866,14 +10904,25 @@ fn fieldPtr( |
| 10866 | 10904 | .Pointer => object_ptr_ty.elemType(), |
| 10867 | 10905 | else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty}), |
| 10868 | 10906 | }; |
| 10869 | switch (object_ty.zigTypeTag()) { | |
| 10907 | ||
| 10908 | // Zig allows dereferencing a single pointer during field lookup. Note that | |
| 10909 | // we don't actually need to generate the dereference some field lookups, like the | |
| 10910 | // length of arrays and other comptime operations. | |
| 10911 | const is_pointer_to = object_ty.isSinglePointer(); | |
| 10912 | ||
| 10913 | const inner_ty = if (is_pointer_to) | |
| 10914 | object_ty.childType() | |
| 10915 | else | |
| 10916 | object_ty; | |
| 10917 | ||
| 10918 | switch (inner_ty.zigTypeTag()) { | |
| 10870 | 10919 | .Array => { |
| 10871 | 10920 | if (mem.eql(u8, field_name, "len")) { |
| 10872 | 10921 | var anon_decl = try block.startAnonDecl(); |
| 10873 | 10922 | defer anon_decl.deinit(); |
| 10874 | 10923 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 10875 | 10924 | Type.initTag(.comptime_int), |
| 10876 | try Value.Tag.int_u64.create(anon_decl.arena(), object_ty.arrayLen()), | |
| 10925 | try Value.Tag.int_u64.create(anon_decl.arena(), inner_ty.arrayLen()), | |
| 10877 | 10926 | )); |
| 10878 | 10927 | } else { |
| 10879 | 10928 | return sema.fail( |
| ... | ... | @@ -10884,77 +10933,74 @@ fn fieldPtr( |
| 10884 | 10933 | ); |
| 10885 | 10934 | } |
| 10886 | 10935 | }, |
| 10887 | .Pointer => switch (object_ty.ptrSize()) { | |
| 10888 | .Slice => { | |
| 10889 | // Here for the ptr and len fields what we need to do is the situation | |
| 10890 | // when a temporary has its address taken, e.g. `&a[c..d].len`. | |
| 10891 | // This value may be known at compile-time or runtime. In the former | |
| 10892 | // case, it should create an anonymous Decl and return a decl_ref to it. | |
| 10893 | // In the latter case, it should add an `alloc` instruction, store | |
| 10894 | // the runtime value to it, and then return the `alloc`. | |
| 10895 | // In both cases the pointer should be const. | |
| 10896 | if (mem.eql(u8, field_name, "ptr")) { | |
| 10897 | return sema.fail( | |
| 10898 | block, | |
| 10899 | field_name_src, | |
| 10900 | "TODO: implement reference to 'ptr' field of slice '{}'", | |
| 10901 | .{object_ty}, | |
| 10902 | ); | |
| 10903 | } else if (mem.eql(u8, field_name, "len")) { | |
| 10904 | return sema.fail( | |
| 10905 | block, | |
| 10906 | field_name_src, | |
| 10907 | "TODO: implement reference to 'len' field of slice '{}'", | |
| 10908 | .{object_ty}, | |
| 10909 | ); | |
| 10910 | } else { | |
| 10911 | return sema.fail( | |
| 10912 | block, | |
| 10913 | field_name_src, | |
| 10914 | "no member named '{s}' in '{}'", | |
| 10915 | .{ field_name, object_ty }, | |
| 10916 | ); | |
| 10936 | .Pointer => if (inner_ty.isSlice()) { | |
| 10937 | const inner_ptr = if (is_pointer_to) | |
| 10938 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) | |
| 10939 | else | |
| 10940 | object_ptr; | |
| 10941 | ||
| 10942 | if (mem.eql(u8, field_name, "ptr")) { | |
| 10943 | const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer); | |
| 10944 | const slice_ptr_ty = inner_ty.slicePtrFieldType(buf); | |
| 10945 | ||
| 10946 | if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { | |
| 10947 | var anon_decl = try block.startAnonDecl(); | |
| 10948 | defer anon_decl.deinit(); | |
| 10949 | ||
| 10950 | return sema.analyzeDeclRef(try anon_decl.finish( | |
| 10951 | try slice_ptr_ty.copy(anon_decl.arena()), | |
| 10952 | try val.slicePtr().copy(anon_decl.arena()), | |
| 10953 | )); | |
| 10917 | 10954 | } |
| 10918 | }, | |
| 10919 | .One => { | |
| 10920 | const ptr_child = object_ty.elemType(); | |
| 10921 | switch (ptr_child.zigTypeTag()) { | |
| 10922 | .Array => { | |
| 10923 | if (mem.eql(u8, field_name, "len")) { | |
| 10924 | var anon_decl = try block.startAnonDecl(); | |
| 10925 | defer anon_decl.deinit(); | |
| 10926 | return sema.analyzeDeclRef(try anon_decl.finish( | |
| 10927 | Type.initTag(.comptime_int), | |
| 10928 | try Value.Tag.int_u64.create(anon_decl.arena(), ptr_child.arrayLen()), | |
| 10929 | )); | |
| 10930 | } else { | |
| 10931 | return sema.fail( | |
| 10932 | block, | |
| 10933 | field_name_src, | |
| 10934 | "no member named '{s}' in '{}'", | |
| 10935 | .{ field_name, object_ty }, | |
| 10936 | ); | |
| 10937 | } | |
| 10938 | }, | |
| 10939 | .Struct => { | |
| 10940 | const struct_ptr_deref = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src); | |
| 10941 | return sema.structFieldPtr(block, src, struct_ptr_deref, field_name, field_name_src, ptr_child); | |
| 10942 | }, | |
| 10943 | .Union => { | |
| 10944 | const union_ptr_deref = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src); | |
| 10945 | return sema.unionFieldPtr(block, src, union_ptr_deref, field_name, field_name_src, ptr_child); | |
| 10946 | }, | |
| 10947 | else => {}, | |
| 10955 | try sema.requireRuntimeBlock(block, src); | |
| 10956 | ||
| 10957 | const result_ty = try Type.ptr(sema.arena, .{ | |
| 10958 | .pointee_type = slice_ptr_ty, | |
| 10959 | .mutable = object_ptr_ty.ptrIsMutable(), | |
| 10960 | .@"addrspace" = object_ptr_ty.ptrAddressSpace(), | |
| 10961 | }); | |
| 10962 | ||
| 10963 | return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr); | |
| 10964 | } else if (mem.eql(u8, field_name, "len")) { | |
| 10965 | if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { | |
| 10966 | var anon_decl = try block.startAnonDecl(); | |
| 10967 | defer anon_decl.deinit(); | |
| 10968 | ||
| 10969 | return sema.analyzeDeclRef(try anon_decl.finish( | |
| 10970 | Type.usize, | |
| 10971 | try Value.Tag.int_u64.create(anon_decl.arena(), val.sliceLen()), | |
| 10972 | )); | |
| 10948 | 10973 | } |
| 10949 | }, | |
| 10950 | .Many, .C => {}, | |
| 10974 | try sema.requireRuntimeBlock(block, src); | |
| 10975 | ||
| 10976 | const result_ty = try Type.ptr(sema.arena, .{ | |
| 10977 | .pointee_type = Type.usize, | |
| 10978 | .mutable = object_ptr_ty.ptrIsMutable(), | |
| 10979 | .@"addrspace" = object_ptr_ty.ptrAddressSpace(), | |
| 10980 | }); | |
| 10981 | ||
| 10982 | return block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr); | |
| 10983 | } else { | |
| 10984 | return sema.fail( | |
| 10985 | block, | |
| 10986 | field_name_src, | |
| 10987 | "no member named '{s}' in '{}'", | |
| 10988 | .{ field_name, object_ty }, | |
| 10989 | ); | |
| 10990 | } | |
| 10951 | 10991 | }, |
| 10952 | 10992 | .Type => { |
| 10953 | 10993 | _ = try sema.resolveConstValue(block, object_ptr_src, object_ptr); |
| 10954 | 10994 | const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src); |
| 10955 | const val = (sema.resolveDefinedValue(block, src, result) catch unreachable).?; | |
| 10995 | const inner = if (is_pointer_to) | |
| 10996 | try sema.analyzeLoad(block, src, result, object_ptr_src) | |
| 10997 | else | |
| 10998 | result; | |
| 10999 | ||
| 11000 | const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?; | |
| 10956 | 11001 | var to_type_buffer: Value.ToTypeBuffer = undefined; |
| 10957 | 11002 | const child_type = val.toType(&to_type_buffer); |
| 11003 | ||
| 10958 | 11004 | switch (child_type.zigTypeTag()) { |
| 10959 | 11005 | .ErrorSet => { |
| 10960 | 11006 | // TODO resolve inferred error sets |
| ... | ... | @@ -10980,22 +11026,24 @@ fn fieldPtr( |
| 10980 | 11026 | try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }), |
| 10981 | 11027 | )); |
| 10982 | 11028 | }, |
| 10983 | .Struct, .Opaque, .Union => { | |
| 11029 | .Union => { | |
| 10984 | 11030 | if (child_type.getNamespace()) |namespace| { |
| 10985 | 11031 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { |
| 10986 | 11032 | return inst; |
| 10987 | 11033 | } |
| 10988 | 11034 | } |
| 10989 | // TODO add note: declared here | |
| 10990 | const kw_name = switch (child_type.zigTypeTag()) { | |
| 10991 | .Struct => "struct", | |
| 10992 | .Opaque => "opaque", | |
| 10993 | .Union => "union", | |
| 10994 | else => unreachable, | |
| 10995 | }; | |
| 10996 | return sema.fail(block, src, "{s} '{}' has no member named '{s}'", .{ | |
| 10997 | kw_name, child_type, field_name, | |
| 10998 | }); | |
| 11035 | if (child_type.unionTagType()) |enum_ty| { | |
| 11036 | if (enum_ty.enumFieldIndex(field_name)) |field_index| { | |
| 11037 | const field_index_u32 = @intCast(u32, field_index); | |
| 11038 | var anon_decl = try block.startAnonDecl(); | |
| 11039 | defer anon_decl.deinit(); | |
| 11040 | return sema.analyzeDeclRef(try anon_decl.finish( | |
| 11041 | try enum_ty.copy(anon_decl.arena()), | |
| 11042 | try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32), | |
| 11043 | )); | |
| 11044 | } | |
| 11045 | } | |
| 11046 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); | |
| 10999 | 11047 | }, |
| 11000 | 11048 | .Enum => { |
| 11001 | 11049 | if (child_type.getNamespace()) |namespace| { |
| ... | ... | @@ -11004,23 +11052,7 @@ fn fieldPtr( |
| 11004 | 11052 | } |
| 11005 | 11053 | } |
| 11006 | 11054 | const field_index = child_type.enumFieldIndex(field_name) orelse { |
| 11007 | const msg = msg: { | |
| 11008 | const msg = try sema.errMsg( | |
| 11009 | block, | |
| 11010 | src, | |
| 11011 | "enum '{}' has no member named '{s}'", | |
| 11012 | .{ child_type, field_name }, | |
| 11013 | ); | |
| 11014 | errdefer msg.destroy(sema.gpa); | |
| 11015 | try sema.mod.errNoteNonLazy( | |
| 11016 | child_type.declSrcLoc(), | |
| 11017 | msg, | |
| 11018 | "enum declared here", | |
| 11019 | .{}, | |
| 11020 | ); | |
| 11021 | break :msg msg; | |
| 11022 | }; | |
| 11023 | return sema.failWithOwnedErrorMsg(msg); | |
| 11055 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); | |
| 11024 | 11056 | }; |
| 11025 | 11057 | const field_index_u32 = @intCast(u32, field_index); |
| 11026 | 11058 | var anon_decl = try block.startAnonDecl(); |
| ... | ... | @@ -11030,14 +11062,34 @@ fn fieldPtr( |
| 11030 | 11062 | try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32), |
| 11031 | 11063 | )); |
| 11032 | 11064 | }, |
| 11065 | .Struct, .Opaque => { | |
| 11066 | if (child_type.getNamespace()) |namespace| { | |
| 11067 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { | |
| 11068 | return inst; | |
| 11069 | } | |
| 11070 | } | |
| 11071 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); | |
| 11072 | }, | |
| 11033 | 11073 | else => return sema.fail(block, src, "type '{}' has no members", .{child_type}), |
| 11034 | 11074 | } |
| 11035 | 11075 | }, |
| 11036 | .Struct => return sema.structFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty), | |
| 11037 | .Union => return sema.unionFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty), | |
| 11076 | .Struct => { | |
| 11077 | const inner_ptr = if (is_pointer_to) | |
| 11078 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) | |
| 11079 | else | |
| 11080 | object_ptr; | |
| 11081 | return sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty); | |
| 11082 | }, | |
| 11083 | .Union => { | |
| 11084 | const inner_ptr = if (is_pointer_to) | |
| 11085 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) | |
| 11086 | else | |
| 11087 | object_ptr; | |
| 11088 | return sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty); | |
| 11089 | }, | |
| 11038 | 11090 | else => {}, |
| 11039 | 11091 | } |
| 11040 | return sema.fail(block, src, "type '{}' does not support field access", .{object_ty}); | |
| 11092 | return sema.fail(block, src, "type '{}' does not support field access (fieldPtr, {}.{s})", .{ object_ty, object_ptr_ty, field_name }); | |
| 11041 | 11093 | } |
| 11042 | 11094 | |
| 11043 | 11095 | fn fieldCallBind( |
| ... | ... | @@ -11209,7 +11261,7 @@ fn structFieldPtr( |
| 11209 | 11261 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| 11210 | 11262 | |
| 11211 | 11263 | const field_index_big = struct_obj.fields.getIndex(field_name) orelse |
| 11212 | return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name); | |
| 11264 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); | |
| 11213 | 11265 | const field_index = @intCast(u32, field_index_big); |
| 11214 | 11266 | const field = struct_obj.fields.values()[field_index]; |
| 11215 | 11267 | const ptr_field_ty = try Type.ptr(arena, .{ |
| ... | ... | @@ -11246,8 +11298,9 @@ fn structFieldVal( |
| 11246 | 11298 | const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty); |
| 11247 | 11299 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| 11248 | 11300 | |
| 11249 | const field_index = struct_obj.fields.getIndex(field_name) orelse | |
| 11250 | return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name); | |
| 11301 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | |
| 11302 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); | |
| 11303 | const field_index = @intCast(u32, field_index_usize); | |
| 11251 | 11304 | const field = struct_obj.fields.values()[field_index]; |
| 11252 | 11305 | |
| 11253 | 11306 | if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| { |
| ... | ... | @@ -11258,16 +11311,7 @@ fn structFieldVal( |
| 11258 | 11311 | } |
| 11259 | 11312 | |
| 11260 | 11313 | try sema.requireRuntimeBlock(block, src); |
| 11261 | return block.addInst(.{ | |
| 11262 | .tag = .struct_field_val, | |
| 11263 | .data = .{ .ty_pl = .{ | |
| 11264 | .ty = try sema.addType(field.ty), | |
| 11265 | .payload = try sema.addExtra(Air.StructField{ | |
| 11266 | .struct_operand = struct_byval, | |
| 11267 | .field_index = @intCast(u32, field_index), | |
| 11268 | }), | |
| 11269 | } }, | |
| 11270 | }); | |
| 11314 | return block.addStructFieldVal(struct_byval, field_index, field.ty); | |
| 11271 | 11315 | } |
| 11272 | 11316 | |
| 11273 | 11317 | fn unionFieldPtr( |
| ... | ... | @@ -11326,8 +11370,9 @@ fn unionFieldVal( |
| 11326 | 11370 | const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty); |
| 11327 | 11371 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; |
| 11328 | 11372 | |
| 11329 | const field_index = union_obj.fields.getIndex(field_name) orelse | |
| 11373 | const field_index_big = union_obj.fields.getIndex(field_name) orelse | |
| 11330 | 11374 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name); |
| 11375 | const field_index = @intCast(u32, field_index_big); | |
| 11331 | 11376 | |
| 11332 | 11377 | const field = union_obj.fields.values()[field_index]; |
| 11333 | 11378 | |
| ... | ... | @@ -11340,7 +11385,7 @@ fn unionFieldVal( |
| 11340 | 11385 | } |
| 11341 | 11386 | |
| 11342 | 11387 | try sema.requireRuntimeBlock(block, src); |
| 11343 | return sema.fail(block, src, "TODO implement runtime union field access", .{}); | |
| 11388 | return block.addStructFieldVal(union_byval, field_index, field.ty); | |
| 11344 | 11389 | } |
| 11345 | 11390 | |
| 11346 | 11391 | fn elemPtr( |
| ... | ... | @@ -13141,6 +13186,10 @@ pub fn resolveTypeLayout( |
| 13141 | 13186 | } |
| 13142 | 13187 | union_obj.status = .have_layout; |
| 13143 | 13188 | }, |
| 13189 | .Array => { | |
| 13190 | const elem_ty = ty.childType(); | |
| 13191 | return sema.resolveTypeLayout(block, src, elem_ty); | |
| 13192 | }, | |
| 13144 | 13193 | else => {}, |
| 13145 | 13194 | } |
| 13146 | 13195 | } |
| ... | ... | @@ -13693,10 +13742,9 @@ fn typeHasOnePossibleValue( |
| 13693 | 13742 | sema: *Sema, |
| 13694 | 13743 | block: *Block, |
| 13695 | 13744 | src: LazySrcLoc, |
| 13696 | starting_type: Type, | |
| 13745 | ty: Type, | |
| 13697 | 13746 | ) CompileError!?Value { |
| 13698 | var ty = starting_type; | |
| 13699 | while (true) switch (ty.tag()) { | |
| 13747 | switch (ty.tag()) { | |
| 13700 | 13748 | .f16, |
| 13701 | 13749 | .f32, |
| 13702 | 13750 | .f64, |
| ... | ... | @@ -13790,7 +13838,7 @@ fn typeHasOnePossibleValue( |
| 13790 | 13838 | const enum_obj = resolved_ty.castTag(.enum_numbered).?.data; |
| 13791 | 13839 | if (enum_obj.fields.count() == 1) { |
| 13792 | 13840 | if (enum_obj.values.count() == 0) { |
| 13793 | return Value.initTag(.zero); // auto-numbered | |
| 13841 | return Value.zero; // auto-numbered | |
| 13794 | 13842 | } else { |
| 13795 | 13843 | return enum_obj.values.keys()[0]; |
| 13796 | 13844 | } |
| ... | ... | @@ -13803,7 +13851,7 @@ fn typeHasOnePossibleValue( |
| 13803 | 13851 | const enum_obj = resolved_ty.castTag(.enum_full).?.data; |
| 13804 | 13852 | if (enum_obj.fields.count() == 1) { |
| 13805 | 13853 | if (enum_obj.values.count() == 0) { |
| 13806 | return Value.initTag(.zero); // auto-numbered | |
| 13854 | return Value.zero; // auto-numbered | |
| 13807 | 13855 | } else { |
| 13808 | 13856 | return enum_obj.values.keys()[0]; |
| 13809 | 13857 | } |
| ... | ... | @@ -13815,12 +13863,19 @@ fn typeHasOnePossibleValue( |
| 13815 | 13863 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); |
| 13816 | 13864 | const enum_simple = resolved_ty.castTag(.enum_simple).?.data; |
| 13817 | 13865 | if (enum_simple.fields.count() == 1) { |
| 13818 | return Value.initTag(.zero); | |
| 13866 | return Value.zero; | |
| 13867 | } else { | |
| 13868 | return null; | |
| 13869 | } | |
| 13870 | }, | |
| 13871 | .enum_nonexhaustive => { | |
| 13872 | const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty; | |
| 13873 | if (!tag_ty.hasCodeGenBits()) { | |
| 13874 | return Value.zero; | |
| 13819 | 13875 | } else { |
| 13820 | 13876 | return null; |
| 13821 | 13877 | } |
| 13822 | 13878 | }, |
| 13823 | .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty, | |
| 13824 | 13879 | .@"union" => { |
| 13825 | 13880 | return null; // TODO |
| 13826 | 13881 | }, |
| ... | ... | @@ -13836,7 +13891,7 @@ fn typeHasOnePossibleValue( |
| 13836 | 13891 | |
| 13837 | 13892 | .int_unsigned, .int_signed => { |
| 13838 | 13893 | if (ty.cast(Type.Payload.Bits).?.data == 0) { |
| 13839 | return Value.initTag(.zero); | |
| 13894 | return Value.zero; | |
| 13840 | 13895 | } else { |
| 13841 | 13896 | return null; |
| 13842 | 13897 | } |
| ... | ... | @@ -13844,14 +13899,16 @@ fn typeHasOnePossibleValue( |
| 13844 | 13899 | .vector, .array, .array_u8 => { |
| 13845 | 13900 | if (ty.arrayLen() == 0) |
| 13846 | 13901 | return Value.initTag(.empty_array); |
| 13847 | ty = ty.elemType(); | |
| 13848 | continue; | |
| 13902 | if ((try sema.typeHasOnePossibleValue(block, src, ty.elemType())) != null) { | |
| 13903 | return Value.initTag(.the_only_possible_value); | |
| 13904 | } | |
| 13905 | return null; | |
| 13849 | 13906 | }, |
| 13850 | 13907 | |
| 13851 | 13908 | .inferred_alloc_const => unreachable, |
| 13852 | 13909 | .inferred_alloc_mut => unreachable, |
| 13853 | 13910 | .generic_poison => return error.GenericPoison, |
| 13854 | }; | |
| 13911 | } | |
| 13855 | 13912 | } |
| 13856 | 13913 | |
| 13857 | 13914 | fn getAstTree(sema: *Sema, block: *Block) CompileError!*const std.zig.Ast { |
src/arch/aarch64/CodeGen.zig+15| ... | ... | @@ -494,6 +494,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 494 | 494 | .slice_ptr => try self.airSlicePtr(inst), |
| 495 | 495 | .slice_len => try self.airSliceLen(inst), |
| 496 | 496 | |
| 497 | .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst), | |
| 498 | .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst), | |
| 499 | ||
| 497 | 500 | .array_elem_val => try self.airArrayElemVal(inst), |
| 498 | 501 | .slice_elem_val => try self.airSliceElemVal(inst), |
| 499 | 502 | .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst), |
| ... | ... | @@ -1057,6 +1060,18 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1057 | 1060 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1058 | 1061 | } |
| 1059 | 1062 | |
| 1063 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { | |
| 1064 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | |
| 1065 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_slice_len_ptr for {}", .{self.target.cpu.arch}); | |
| 1066 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | |
| 1067 | } | |
| 1068 | ||
| 1069 | fn airPtrSlicePtrPtr(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 ptr_slice_ptr_ptr for {}", .{self.target.cpu.arch}); | |
| 1072 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | |
| 1073 | } | |
| 1074 | ||
| 1060 | 1075 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1061 | 1076 | const is_volatile = false; // TODO |
| 1062 | 1077 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
src/codegen.zig+19| ... | ... | @@ -842,6 +842,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 842 | 842 | .slice_ptr => try self.airSlicePtr(inst), |
| 843 | 843 | .slice_len => try self.airSliceLen(inst), |
| 844 | 844 | |
| 845 | .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst), | |
| 846 | .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst), | |
| 847 | ||
| 845 | 848 | .array_elem_val => try self.airArrayElemVal(inst), |
| 846 | 849 | .slice_elem_val => try self.airSliceElemVal(inst), |
| 847 | 850 | .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst), |
| ... | ... | @@ -1498,6 +1501,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1498 | 1501 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1499 | 1502 | } |
| 1500 | 1503 | |
| 1504 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { | |
| 1505 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | |
| 1506 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) { | |
| 1507 | else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{self.target.cpu.arch}), | |
| 1508 | }; | |
| 1509 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | |
| 1510 | } | |
| 1511 | ||
| 1512 | fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { | |
| 1513 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | |
| 1514 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) { | |
| 1515 | else => return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{self.target.cpu.arch}), | |
| 1516 | }; | |
| 1517 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | |
| 1518 | } | |
| 1519 | ||
| 1501 | 1520 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1502 | 1521 | const is_volatile = false; // TODO |
| 1503 | 1522 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
src/codegen/c.zig+18| ... | ... | @@ -1075,6 +1075,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1075 | 1075 | .slice_ptr => try airSliceField(f, inst, ".ptr;\n"), |
| 1076 | 1076 | .slice_len => try airSliceField(f, inst, ".len;\n"), |
| 1077 | 1077 | |
| 1078 | .ptr_slice_len_ptr => try airPtrSliceFieldPtr(f, inst, ".len;\n"), | |
| 1079 | .ptr_slice_ptr_ptr => try airPtrSliceFieldPtr(f, inst, ".ptr;\n"), | |
| 1080 | ||
| 1078 | 1081 | .ptr_elem_val => try airPtrElemVal(f, inst, "["), |
| 1079 | 1082 | .ptr_ptr_elem_val => try airPtrElemVal(f, inst, "[0]["), |
| 1080 | 1083 | .ptr_elem_ptr => try airPtrElemPtr(f, inst), |
| ... | ... | @@ -1114,6 +1117,21 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue |
| 1114 | 1117 | return local; |
| 1115 | 1118 | } |
| 1116 | 1119 | |
| 1120 | fn airPtrSliceFieldPtr(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue { | |
| 1121 | if (f.liveness.isUnused(inst)) | |
| 1122 | return CValue.none; | |
| 1123 | ||
| 1124 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | |
| 1125 | const operand = try f.resolveInst(ty_op.operand); | |
| 1126 | const writer = f.object.writer(); | |
| 1127 | ||
| 1128 | _ = writer; | |
| 1129 | _ = operand; | |
| 1130 | _ = suffix; | |
| 1131 | ||
| 1132 | return f.fail("TODO: C backend: airPtrSliceFieldPtr", .{}); | |
| 1133 | } | |
| 1134 | ||
| 1117 | 1135 | fn airPtrElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue { |
| 1118 | 1136 | const is_volatile = false; // TODO |
| 1119 | 1137 | if (!is_volatile and f.liveness.isUnused(inst)) |
src/codegen/llvm.zig+44-10| ... | ... | @@ -1261,6 +1261,10 @@ pub const DeclGen = struct { |
| 1261 | 1261 | } |
| 1262 | 1262 | const field_ty = tv.ty.unionFieldType(tag_and_val.tag); |
| 1263 | 1263 | const payload = p: { |
| 1264 | if (!field_ty.hasCodeGenBits()) { | |
| 1265 | const padding_len = @intCast(c_uint, layout.payload_size); | |
| 1266 | break :p self.context.intType(8).arrayType(padding_len).getUndef(); | |
| 1267 | } | |
| 1264 | 1268 | const field = try genTypedValue(self, .{ .ty = field_ty, .val = tag_and_val.val }); |
| 1265 | 1269 | const field_size = field_ty.abiSize(target); |
| 1266 | 1270 | if (field_size == layout.payload_size) { |
| ... | ... | @@ -1709,6 +1713,10 @@ pub const FuncGen = struct { |
| 1709 | 1713 | .assembly => try self.airAssembly(inst), |
| 1710 | 1714 | .slice_ptr => try self.airSliceField(inst, 0), |
| 1711 | 1715 | .slice_len => try self.airSliceField(inst, 1), |
| 1716 | ||
| 1717 | .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0), | |
| 1718 | .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1), | |
| 1719 | ||
| 1712 | 1720 | .array_to_slice => try self.airArrayToSlice(inst), |
| 1713 | 1721 | .float_to_int => try self.airFloatToInt(inst), |
| 1714 | 1722 | .int_to_float => try self.airIntToFloat(inst), |
| ... | ... | @@ -2091,6 +2099,15 @@ pub const FuncGen = struct { |
| 2091 | 2099 | return self.builder.buildExtractValue(operand, index, ""); |
| 2092 | 2100 | } |
| 2093 | 2101 | |
| 2102 | fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value { | |
| 2103 | if (self.liveness.isUnused(inst)) return null; | |
| 2104 | ||
| 2105 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | |
| 2106 | const slice_ptr = try self.resolveInst(ty_op.operand); | |
| 2107 | ||
| 2108 | return self.builder.buildStructGEP(slice_ptr, index, ""); | |
| 2109 | } | |
| 2110 | ||
| 2094 | 2111 | fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 2095 | 2112 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2096 | 2113 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| ... | ... | @@ -2223,17 +2240,34 @@ pub const FuncGen = struct { |
| 2223 | 2240 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 2224 | 2241 | const struct_ty = self.air.typeOf(struct_field.struct_operand); |
| 2225 | 2242 | const struct_llvm_val = try self.resolveInst(struct_field.struct_operand); |
| 2226 | const field_index = llvmFieldIndex(struct_ty, struct_field.field_index); | |
| 2227 | if (isByRef(struct_ty)) { | |
| 2228 | const field_ptr = self.builder.buildStructGEP(struct_llvm_val, field_index, ""); | |
| 2229 | const field_ty = struct_ty.structFieldType(struct_field.field_index); | |
| 2230 | if (isByRef(field_ty)) { | |
| 2231 | return field_ptr; | |
| 2232 | } else { | |
| 2233 | return self.builder.buildLoad(field_ptr, ""); | |
| 2234 | } | |
| 2243 | const field_index = struct_field.field_index; | |
| 2244 | const field_ty = struct_ty.structFieldType(field_index); | |
| 2245 | if (!field_ty.hasCodeGenBits()) { | |
| 2246 | return null; | |
| 2247 | } | |
| 2248 | ||
| 2249 | assert(isByRef(struct_ty)); | |
| 2250 | ||
| 2251 | const field_ptr = switch (struct_ty.zigTypeTag()) { | |
| 2252 | .Struct => blk: { | |
| 2253 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index); | |
| 2254 | break :blk self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, ""); | |
| 2255 | }, | |
| 2256 | .Union => blk: { | |
| 2257 | const llvm_field_ty = try self.dg.llvmType(field_ty); | |
| 2258 | const target = self.dg.module.getTarget(); | |
| 2259 | const layout = struct_ty.unionGetLayout(target); | |
| 2260 | const payload_index = @boolToInt(layout.tag_align >= layout.payload_align); | |
| 2261 | const union_field_ptr = self.builder.buildStructGEP(struct_llvm_val, payload_index, ""); | |
| 2262 | break :blk self.builder.buildBitCast(union_field_ptr, llvm_field_ty.pointerType(0), ""); | |
| 2263 | }, | |
| 2264 | else => unreachable, | |
| 2265 | }; | |
| 2266 | ||
| 2267 | if (isByRef(field_ty)) { | |
| 2268 | return field_ptr; | |
| 2235 | 2269 | } else { |
| 2236 | return self.builder.buildExtractValue(struct_llvm_val, field_index, ""); | |
| 2270 | return self.builder.buildLoad(field_ptr, ""); | |
| 2237 | 2271 | } |
| 2238 | 2272 | } |
| 2239 | 2273 |
src/codegen/wasm.zig+10| ... | ... | @@ -866,6 +866,7 @@ pub const Context = struct { |
| 866 | 866 | .struct_field_ptr_index_1 => self.airStructFieldPtrIndex(inst, 1), |
| 867 | 867 | .struct_field_ptr_index_2 => self.airStructFieldPtrIndex(inst, 2), |
| 868 | 868 | .struct_field_ptr_index_3 => self.airStructFieldPtrIndex(inst, 3), |
| 869 | .struct_field_val => self.airStructFieldVal(inst), | |
| 869 | 870 | .switch_br => self.airSwitchBr(inst), |
| 870 | 871 | .unreach => self.airUnreachable(inst), |
| 871 | 872 | .wrap_optional => self.airWrapOptional(inst), |
| ... | ... | @@ -1456,6 +1457,15 @@ pub const Context = struct { |
| 1456 | 1457 | return WValue{ .local = struct_ptr.multi_value.index + index }; |
| 1457 | 1458 | } |
| 1458 | 1459 | |
| 1460 | fn airStructFieldVal(self: *Context, inst: Air.Inst.Index) InnerError!WValue { | |
| 1461 | if (self.liveness.isUnused(inst)) return WValue.none; | |
| 1462 | ||
| 1463 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 1464 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | |
| 1465 | const struct_multivalue = self.resolveInst(extra.struct_operand).multi_value; | |
| 1466 | return WValue{ .local = struct_multivalue.index + extra.field_index }; | |
| 1467 | } | |
| 1468 | ||
| 1459 | 1469 | fn airSwitchBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue { |
| 1460 | 1470 | // result type is always 'noreturn' |
| 1461 | 1471 | const blocktype = wasm.block_empty; |
src/print_air.zig+2| ... | ... | @@ -183,6 +183,8 @@ const Writer = struct { |
| 183 | 183 | .wrap_errunion_err, |
| 184 | 184 | .slice_ptr, |
| 185 | 185 | .slice_len, |
| 186 | .ptr_slice_len_ptr, | |
| 187 | .ptr_slice_ptr_ptr, | |
| 186 | 188 | .struct_field_ptr_index_0, |
| 187 | 189 | .struct_field_ptr_index_1, |
| 188 | 190 | .struct_field_ptr_index_2, |
src/type.zig+24-9| ... | ... | @@ -2676,7 +2676,7 @@ pub const Type = extern union { |
| 2676 | 2676 | |
| 2677 | 2677 | .pointer => return self.castTag(.pointer).?.data.sentinel, |
| 2678 | 2678 | .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel, |
| 2679 | .array_u8_sentinel_0 => return Value.initTag(.zero), | |
| 2679 | .array_u8_sentinel_0 => return Value.zero, | |
| 2680 | 2680 | |
| 2681 | 2681 | else => unreachable, |
| 2682 | 2682 | }; |
| ... | ... | @@ -3096,6 +3096,14 @@ pub const Type = extern union { |
| 3096 | 3096 | } |
| 3097 | 3097 | return Value.initTag(.empty_struct_value); |
| 3098 | 3098 | }, |
| 3099 | .enum_numbered => { | |
| 3100 | const enum_numbered = ty.castTag(.enum_numbered).?.data; | |
| 3101 | if (enum_numbered.fields.count() == 1) { | |
| 3102 | return enum_numbered.values.keys()[0]; | |
| 3103 | } else { | |
| 3104 | return null; | |
| 3105 | } | |
| 3106 | }, | |
| 3099 | 3107 | .enum_full => { |
| 3100 | 3108 | const enum_full = ty.castTag(.enum_full).?.data; |
| 3101 | 3109 | if (enum_full.fields.count() == 1) { |
| ... | ... | @@ -3107,13 +3115,19 @@ pub const Type = extern union { |
| 3107 | 3115 | .enum_simple => { |
| 3108 | 3116 | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 3109 | 3117 | if (enum_simple.fields.count() == 1) { |
| 3110 | return Value.initTag(.zero); | |
| 3118 | return Value.zero; | |
| 3119 | } else { | |
| 3120 | return null; | |
| 3121 | } | |
| 3122 | }, | |
| 3123 | .enum_nonexhaustive => { | |
| 3124 | const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty; | |
| 3125 | if (!tag_ty.hasCodeGenBits()) { | |
| 3126 | return Value.zero; | |
| 3111 | 3127 | } else { |
| 3112 | 3128 | return null; |
| 3113 | 3129 | } |
| 3114 | 3130 | }, |
| 3115 | .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty, | |
| 3116 | .enum_numbered => ty = ty.castTag(.enum_numbered).?.data.tag_ty, | |
| 3117 | 3131 | .@"union" => { |
| 3118 | 3132 | return null; // TODO |
| 3119 | 3133 | }, |
| ... | ... | @@ -3129,7 +3143,7 @@ pub const Type = extern union { |
| 3129 | 3143 | |
| 3130 | 3144 | .int_unsigned, .int_signed => { |
| 3131 | 3145 | if (ty.cast(Payload.Bits).?.data == 0) { |
| 3132 | return Value.initTag(.zero); | |
| 3146 | return Value.zero; | |
| 3133 | 3147 | } else { |
| 3134 | 3148 | return null; |
| 3135 | 3149 | } |
| ... | ... | @@ -3137,8 +3151,9 @@ pub const Type = extern union { |
| 3137 | 3151 | .vector, .array, .array_u8 => { |
| 3138 | 3152 | if (ty.arrayLen() == 0) |
| 3139 | 3153 | return Value.initTag(.empty_array); |
| 3140 | ty = ty.elemType(); | |
| 3141 | continue; | |
| 3154 | if (ty.elemType().onePossibleValue() != null) | |
| 3155 | return Value.initTag(.the_only_possible_value); | |
| 3156 | return null; | |
| 3142 | 3157 | }, |
| 3143 | 3158 | |
| 3144 | 3159 | .inferred_alloc_const => unreachable, |
| ... | ... | @@ -3179,7 +3194,7 @@ pub const Type = extern union { |
| 3179 | 3194 | const info = self.intInfo(target); |
| 3180 | 3195 | |
| 3181 | 3196 | if (info.signedness == .unsigned) { |
| 3182 | return Value.initTag(.zero); | |
| 3197 | return Value.zero; | |
| 3183 | 3198 | } |
| 3184 | 3199 | |
| 3185 | 3200 | if (info.bits <= 6) { |
| ... | ... | @@ -4013,7 +4028,7 @@ pub const Type = extern union { |
| 4013 | 4028 | ) Allocator.Error!Type { |
| 4014 | 4029 | if (elem_type.eql(Type.u8)) { |
| 4015 | 4030 | if (sent) |some| { |
| 4016 | if (some.eql(Value.initTag(.zero), elem_type)) { | |
| 4031 | if (some.eql(Value.zero, elem_type)) { | |
| 4017 | 4032 | return Tag.array_u8_sentinel_0.create(arena, len); |
| 4018 | 4033 | } |
| 4019 | 4034 | } else { |
src/value.zig+74-37| ... | ... | @@ -86,6 +86,8 @@ pub const Value = extern union { |
| 86 | 86 | one, |
| 87 | 87 | void_value, |
| 88 | 88 | unreachable_value, |
| 89 | /// The only possible value for a particular type, which is stored externally. | |
| 90 | the_only_possible_value, | |
| 89 | 91 | null_value, |
| 90 | 92 | bool_true, |
| 91 | 93 | bool_false, |
| ... | ... | @@ -226,6 +228,7 @@ pub const Value = extern union { |
| 226 | 228 | .one, |
| 227 | 229 | .void_value, |
| 228 | 230 | .unreachable_value, |
| 231 | .the_only_possible_value, | |
| 229 | 232 | .empty_struct_value, |
| 230 | 233 | .empty_array, |
| 231 | 234 | .null_value, |
| ... | ... | @@ -415,6 +418,7 @@ pub const Value = extern union { |
| 415 | 418 | .one, |
| 416 | 419 | .void_value, |
| 417 | 420 | .unreachable_value, |
| 421 | .the_only_possible_value, | |
| 418 | 422 | .empty_array, |
| 419 | 423 | .null_value, |
| 420 | 424 | .bool_true, |
| ... | ... | @@ -664,6 +668,7 @@ pub const Value = extern union { |
| 664 | 668 | .one => return out_stream.writeAll("1"), |
| 665 | 669 | .void_value => return out_stream.writeAll("{}"), |
| 666 | 670 | .unreachable_value => return out_stream.writeAll("unreachable"), |
| 671 | .the_only_possible_value => return out_stream.writeAll("(the only possible value)"), | |
| 667 | 672 | .bool_true => return out_stream.writeAll("true"), |
| 668 | 673 | .bool_false => return out_stream.writeAll("false"), |
| 669 | 674 | .ty => return val.castTag(.ty).?.data.format("", options, out_stream), |
| ... | ... | @@ -755,6 +760,7 @@ pub const Value = extern union { |
| 755 | 760 | const decl_val = try decl.value(); |
| 756 | 761 | return decl_val.toAllocatedBytes(decl.ty, allocator); |
| 757 | 762 | }, |
| 763 | .the_only_possible_value => return &[_]u8{}, | |
| 758 | 764 | else => unreachable, |
| 759 | 765 | } |
| 760 | 766 | } |
| ... | ... | @@ -847,53 +853,63 @@ pub const Value = extern union { |
| 847 | 853 | // TODO should `@intToEnum` do this `@intCast` for you? |
| 848 | 854 | return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index)); |
| 849 | 855 | }, |
| 856 | .the_only_possible_value => { | |
| 857 | const fields = std.meta.fields(E); | |
| 858 | assert(fields.len == 1); | |
| 859 | return @intToEnum(E, fields[0].value); | |
| 860 | }, | |
| 850 | 861 | else => unreachable, |
| 851 | 862 | } |
| 852 | 863 | } |
| 853 | 864 | |
| 854 | 865 | pub fn enumToInt(val: Value, ty: Type, buffer: *Payload.U64) Value { |
| 855 | if (val.castTag(.enum_field_index)) |enum_field_payload| { | |
| 856 | const field_index = enum_field_payload.data; | |
| 857 | switch (ty.tag()) { | |
| 858 | .enum_full, .enum_nonexhaustive => { | |
| 859 | const enum_full = ty.cast(Type.Payload.EnumFull).?.data; | |
| 860 | if (enum_full.values.count() != 0) { | |
| 861 | return enum_full.values.keys()[field_index]; | |
| 862 | } else { | |
| 863 | // Field index and integer values are the same. | |
| 864 | buffer.* = .{ | |
| 865 | .base = .{ .tag = .int_u64 }, | |
| 866 | .data = field_index, | |
| 867 | }; | |
| 868 | return Value.initPayload(&buffer.base); | |
| 869 | } | |
| 870 | }, | |
| 871 | .enum_numbered => { | |
| 872 | const enum_obj = ty.castTag(.enum_numbered).?.data; | |
| 873 | if (enum_obj.values.count() != 0) { | |
| 874 | return enum_obj.values.keys()[field_index]; | |
| 875 | } else { | |
| 876 | // Field index and integer values are the same. | |
| 877 | buffer.* = .{ | |
| 878 | .base = .{ .tag = .int_u64 }, | |
| 879 | .data = field_index, | |
| 880 | }; | |
| 881 | return Value.initPayload(&buffer.base); | |
| 882 | } | |
| 883 | }, | |
| 884 | .enum_simple => { | |
| 866 | const field_index = switch (val.tag()) { | |
| 867 | .enum_field_index => val.castTag(.enum_field_index).?.data, | |
| 868 | .the_only_possible_value => blk: { | |
| 869 | assert(ty.enumFieldCount() == 1); | |
| 870 | break :blk 0; | |
| 871 | }, | |
| 872 | // Assume it is already an integer and return it directly. | |
| 873 | else => return val, | |
| 874 | }; | |
| 875 | ||
| 876 | switch (ty.tag()) { | |
| 877 | .enum_full, .enum_nonexhaustive => { | |
| 878 | const enum_full = ty.cast(Type.Payload.EnumFull).?.data; | |
| 879 | if (enum_full.values.count() != 0) { | |
| 880 | return enum_full.values.keys()[field_index]; | |
| 881 | } else { | |
| 885 | 882 | // Field index and integer values are the same. |
| 886 | 883 | buffer.* = .{ |
| 887 | 884 | .base = .{ .tag = .int_u64 }, |
| 888 | 885 | .data = field_index, |
| 889 | 886 | }; |
| 890 | 887 | return Value.initPayload(&buffer.base); |
| 891 | }, | |
| 892 | else => unreachable, | |
| 893 | } | |
| 888 | } | |
| 889 | }, | |
| 890 | .enum_numbered => { | |
| 891 | const enum_obj = ty.castTag(.enum_numbered).?.data; | |
| 892 | if (enum_obj.values.count() != 0) { | |
| 893 | return enum_obj.values.keys()[field_index]; | |
| 894 | } else { | |
| 895 | // Field index and integer values are the same. | |
| 896 | buffer.* = .{ | |
| 897 | .base = .{ .tag = .int_u64 }, | |
| 898 | .data = field_index, | |
| 899 | }; | |
| 900 | return Value.initPayload(&buffer.base); | |
| 901 | } | |
| 902 | }, | |
| 903 | .enum_simple => { | |
| 904 | // Field index and integer values are the same. | |
| 905 | buffer.* = .{ | |
| 906 | .base = .{ .tag = .int_u64 }, | |
| 907 | .data = field_index, | |
| 908 | }; | |
| 909 | return Value.initPayload(&buffer.base); | |
| 910 | }, | |
| 911 | else => unreachable, | |
| 894 | 912 | } |
| 895 | // Assume it is already an integer and return it directly. | |
| 896 | return val; | |
| 897 | 913 | } |
| 898 | 914 | |
| 899 | 915 | /// Asserts the value is an integer. |
| ... | ... | @@ -901,6 +917,7 @@ pub const Value = extern union { |
| 901 | 917 | switch (self.tag()) { |
| 902 | 918 | .zero, |
| 903 | 919 | .bool_false, |
| 920 | .the_only_possible_value, // i0, u0 | |
| 904 | 921 | => return BigIntMutable.init(&space.limbs, 0).toConst(), |
| 905 | 922 | |
| 906 | 923 | .one, |
| ... | ... | @@ -922,6 +939,7 @@ pub const Value = extern union { |
| 922 | 939 | switch (self.tag()) { |
| 923 | 940 | .zero, |
| 924 | 941 | .bool_false, |
| 942 | .the_only_possible_value, // i0, u0 | |
| 925 | 943 | => return 0, |
| 926 | 944 | |
| 927 | 945 | .one, |
| ... | ... | @@ -943,6 +961,7 @@ pub const Value = extern union { |
| 943 | 961 | switch (self.tag()) { |
| 944 | 962 | .zero, |
| 945 | 963 | .bool_false, |
| 964 | .the_only_possible_value, // i0, u0 | |
| 946 | 965 | => return 0, |
| 947 | 966 | |
| 948 | 967 | .one, |
| ... | ... | @@ -1124,6 +1143,11 @@ pub const Value = extern union { |
| 1124 | 1143 | @panic("TODO implement int_big_negative Value clz"); |
| 1125 | 1144 | }, |
| 1126 | 1145 | |
| 1146 | .the_only_possible_value => { | |
| 1147 | assert(ty_bits == 0); | |
| 1148 | return ty_bits; | |
| 1149 | }, | |
| 1150 | ||
| 1127 | 1151 | else => unreachable, |
| 1128 | 1152 | } |
| 1129 | 1153 | } |
| ... | ... | @@ -1134,6 +1158,7 @@ pub const Value = extern union { |
| 1134 | 1158 | switch (self.tag()) { |
| 1135 | 1159 | .zero, |
| 1136 | 1160 | .bool_false, |
| 1161 | .the_only_possible_value, | |
| 1137 | 1162 | => return 0, |
| 1138 | 1163 | |
| 1139 | 1164 | .one, |
| ... | ... | @@ -1213,6 +1238,11 @@ pub const Value = extern union { |
| 1213 | 1238 | else => unreachable, |
| 1214 | 1239 | }, |
| 1215 | 1240 | |
| 1241 | .the_only_possible_value => { | |
| 1242 | assert(ty.intInfo(target).bits == 0); | |
| 1243 | return true; | |
| 1244 | }, | |
| 1245 | ||
| 1216 | 1246 | else => unreachable, |
| 1217 | 1247 | } |
| 1218 | 1248 | } |
| ... | ... | @@ -1251,7 +1281,7 @@ pub const Value = extern union { |
| 1251 | 1281 | /// Asserts the value is numeric |
| 1252 | 1282 | pub fn isZero(self: Value) bool { |
| 1253 | 1283 | return switch (self.tag()) { |
| 1254 | .zero => true, | |
| 1284 | .zero, .the_only_possible_value => true, | |
| 1255 | 1285 | .one => false, |
| 1256 | 1286 | |
| 1257 | 1287 | .int_u64 => self.castTag(.int_u64).?.data == 0, |
| ... | ... | @@ -1272,6 +1302,7 @@ pub const Value = extern union { |
| 1272 | 1302 | return switch (lhs.tag()) { |
| 1273 | 1303 | .zero, |
| 1274 | 1304 | .bool_false, |
| 1305 | .the_only_possible_value, | |
| 1275 | 1306 | => .eq, |
| 1276 | 1307 | |
| 1277 | 1308 | .one, |
| ... | ... | @@ -1354,7 +1385,7 @@ pub const Value = extern union { |
| 1354 | 1385 | assert(b_tag != .undef); |
| 1355 | 1386 | if (a_tag == b_tag) { |
| 1356 | 1387 | switch (a_tag) { |
| 1357 | .void_value, .null_value => return true, | |
| 1388 | .void_value, .null_value, .the_only_possible_value => return true, | |
| 1358 | 1389 | .enum_literal => { |
| 1359 | 1390 | const a_name = a.castTag(.enum_literal).?.data; |
| 1360 | 1391 | const b_name = b.castTag(.enum_literal).?.data; |
| ... | ... | @@ -1706,6 +1737,9 @@ pub const Value = extern union { |
| 1706 | 1737 | .decl_ref => return val.castTag(.decl_ref).?.data.val.elemValueAdvanced(index, arena, buffer), |
| 1707 | 1738 | .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.val.elemValueAdvanced(index, arena, buffer), |
| 1708 | 1739 | |
| 1740 | // The child type of arrays which have only one possible value need to have only one possible value itself. | |
| 1741 | .the_only_possible_value => return val, | |
| 1742 | ||
| 1709 | 1743 | else => unreachable, |
| 1710 | 1744 | } |
| 1711 | 1745 | } |
| ... | ... | @@ -1722,6 +1756,8 @@ pub const Value = extern union { |
| 1722 | 1756 | // TODO assert the tag is correct |
| 1723 | 1757 | return payload.val; |
| 1724 | 1758 | }, |
| 1759 | // Structs which have only one possible value need to consist of members which have only one possible value. | |
| 1760 | .the_only_possible_value => return val, | |
| 1725 | 1761 | |
| 1726 | 1762 | else => unreachable, |
| 1727 | 1763 | } |
| ... | ... | @@ -1820,6 +1856,7 @@ pub const Value = extern union { |
| 1820 | 1856 | pub fn intToFloat(val: Value, allocator: *Allocator, dest_ty: Type, target: Target) !Value { |
| 1821 | 1857 | switch (val.tag()) { |
| 1822 | 1858 | .undef, .zero, .one => return val, |
| 1859 | .the_only_possible_value => return Value.initTag(.zero), // for i0, u0 | |
| 1823 | 1860 | .int_u64 => { |
| 1824 | 1861 | return intToFloatInner(val.castTag(.int_u64).?.data, allocator, dest_ty, target); |
| 1825 | 1862 | }, |