| 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,6 +367,12 @@ pub const Inst = struct { |
| 367 | /// Given a slice value, return the pointer. | 367 | /// Given a slice value, return the pointer. |
| 368 | /// Uses the `ty_op` field. | 368 | /// Uses the `ty_op` field. |
| 369 | slice_ptr, | 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 | /// Given an array value and element index, return the element value at that index. | 376 | /// Given an array value and element index, return the element value at that index. |
| 371 | /// Result type is the element type of the array operand. | 377 | /// Result type is the element type of the array operand. |
| 372 | /// Uses the `bin_op` field. | 378 | /// Uses the `bin_op` field. |
| ... | @@ -707,6 +713,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -707,6 +713,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 707 | .wrap_errunion_payload, | 713 | .wrap_errunion_payload, |
| 708 | .wrap_errunion_err, | 714 | .wrap_errunion_err, |
| 709 | .slice_ptr, | 715 | .slice_ptr, |
| 716 | .ptr_slice_len_ptr, | ||
| 717 | .ptr_slice_ptr_ptr, | ||
| 710 | .struct_field_ptr_index_0, | 718 | .struct_field_ptr_index_0, |
| 711 | .struct_field_ptr_index_1, | 719 | .struct_field_ptr_index_1, |
| 712 | .struct_field_ptr_index_2, | 720 | .struct_field_ptr_index_2, |
src/AstGen.zig+16-21| ... | @@ -193,9 +193,6 @@ pub const ResultLoc = union(enum) { | ... | @@ -193,9 +193,6 @@ pub const ResultLoc = union(enum) { |
| 193 | /// The expression must generate a pointer rather than a value. For example, the left hand side | 193 | /// The expression must generate a pointer rather than a value. For example, the left hand side |
| 194 | /// of an assignment uses this kind of result location. | 194 | /// of an assignment uses this kind of result location. |
| 195 | ref, | 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 | /// The expression will be coerced into this type, but it will be evaluated as an rvalue. | 196 | /// The expression will be coerced into this type, but it will be evaluated as an rvalue. |
| 200 | ty: Zir.Inst.Ref, | 197 | ty: Zir.Inst.Ref, |
| 201 | /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion, | 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,7 +228,7 @@ pub const ResultLoc = union(enum) { |
| 231 | fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy { | 228 | fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy { |
| 232 | switch (rl) { | 229 | switch (rl) { |
| 233 | // In this branch there will not be any store_to_block_ptr instructions. | 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 | .tag = .break_operand, | 232 | .tag = .break_operand, |
| 236 | .elide_store_to_block_ptr_instructions = false, | 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,7 +724,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 727 | .start = start, | 724 | .start = start, |
| 728 | }); | 725 | }); |
| 729 | switch (rl) { | 726 | switch (rl) { |
| 730 | .ref, .none_or_ref => return result, | 727 | .ref => return result, |
| 731 | else => { | 728 | else => { |
| 732 | const dereffed = try gz.addUnNode(.load, result, node); | 729 | const dereffed = try gz.addUnNode(.load, result, node); |
| 733 | return rvalue(gz, rl, dereffed, node); | 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,7 +742,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 745 | .end = end, | 742 | .end = end, |
| 746 | }); | 743 | }); |
| 747 | switch (rl) { | 744 | switch (rl) { |
| 748 | .ref, .none_or_ref => return result, | 745 | .ref => return result, |
| 749 | else => { | 746 | else => { |
| 750 | const dereffed = try gz.addUnNode(.load, result, node); | 747 | const dereffed = try gz.addUnNode(.load, result, node); |
| 751 | return rvalue(gz, rl, dereffed, node); | 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,7 +762,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 765 | .sentinel = sentinel, | 762 | .sentinel = sentinel, |
| 766 | }); | 763 | }); |
| 767 | switch (rl) { | 764 | switch (rl) { |
| 768 | .ref, .none_or_ref => return result, | 765 | .ref => return result, |
| 769 | else => { | 766 | else => { |
| 770 | const dereffed = try gz.addUnNode(.load, result, node); | 767 | const dereffed = try gz.addUnNode(.load, result, node); |
| 771 | return rvalue(gz, rl, dereffed, node); | 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,7 +773,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 776 | .deref => { | 773 | .deref => { |
| 777 | const lhs = try expr(gz, scope, .none, node_datas[node].lhs); | 774 | const lhs = try expr(gz, scope, .none, node_datas[node].lhs); |
| 778 | switch (rl) { | 775 | switch (rl) { |
| 779 | .ref, .none_or_ref => return lhs, | 776 | .ref => return lhs, |
| 780 | else => { | 777 | else => { |
| 781 | const result = try gz.addUnNode(.load, lhs, node); | 778 | const result = try gz.addUnNode(.load, lhs, node); |
| 782 | return rvalue(gz, rl, result, node); | 779 | return rvalue(gz, rl, result, node); |
| ... | @@ -1273,7 +1270,7 @@ fn arrayInitExpr( | ... | @@ -1273,7 +1270,7 @@ fn arrayInitExpr( |
| 1273 | return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref); | 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 | if (types.array != .none) { | 1274 | if (types.array != .none) { |
| 1278 | return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init); | 1275 | return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init); |
| 1279 | } else { | 1276 | } else { |
| ... | @@ -1475,7 +1472,7 @@ fn structInitExpr( | ... | @@ -1475,7 +1472,7 @@ fn structInitExpr( |
| 1475 | return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref); | 1472 | return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref); |
| 1476 | } | 1473 | } |
| 1477 | }, | 1474 | }, |
| 1478 | .none, .none_or_ref => { | 1475 | .none => { |
| 1479 | if (struct_init.ast.type_expr != 0) { | 1476 | if (struct_init.ast.type_expr != 0) { |
| 1480 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); | 1477 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1481 | return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); | 1478 | return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); |
| ... | @@ -5133,7 +5130,7 @@ fn fieldAccess( | ... | @@ -5133,7 +5130,7 @@ fn fieldAccess( |
| 5133 | if (rl == .ref) { | 5130 | if (rl == .ref) { |
| 5134 | return addFieldAccess(.field_ptr, gz, scope, .ref, node); | 5131 | return addFieldAccess(.field_ptr, gz, scope, .ref, node); |
| 5135 | } else { | 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 | return rvalue(gz, rl, access, node); | 5134 | return rvalue(gz, rl, access, node); |
| 5138 | } | 5135 | } |
| 5139 | } | 5136 | } |
| ... | @@ -5178,7 +5175,7 @@ fn arrayAccess( | ... | @@ -5178,7 +5175,7 @@ fn arrayAccess( |
| 5178 | ), | 5175 | ), |
| 5179 | else => return rvalue(gz, rl, try gz.addBin( | 5176 | else => return rvalue(gz, rl, try gz.addBin( |
| 5180 | .elem_val, | 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 | try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), | 5179 | try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), |
| 5183 | ), node), | 5180 | ), node), |
| 5184 | } | 5181 | } |
| ... | @@ -6664,7 +6661,7 @@ fn identifier( | ... | @@ -6664,7 +6661,7 @@ fn identifier( |
| 6664 | ); | 6661 | ); |
| 6665 | 6662 | ||
| 6666 | switch (rl) { | 6663 | switch (rl) { |
| 6667 | .ref, .none_or_ref => return ptr_inst, | 6664 | .ref => return ptr_inst, |
| 6668 | else => { | 6665 | else => { |
| 6669 | const loaded = try gz.addUnNode(.load, ptr_inst, ident); | 6666 | const loaded = try gz.addUnNode(.load, ptr_inst, ident); |
| 6670 | return rvalue(gz, rl, loaded, ident); | 6667 | return rvalue(gz, rl, loaded, ident); |
| ... | @@ -6700,7 +6697,7 @@ fn identifier( | ... | @@ -6700,7 +6697,7 @@ fn identifier( |
| 6700 | // Decl references happen by name rather than ZIR index so that when unrelated | 6697 | // Decl references happen by name rather than ZIR index so that when unrelated |
| 6701 | // decls are modified, ZIR code containing references to them can be unmodified. | 6698 | // decls are modified, ZIR code containing references to them can be unmodified. |
| 6702 | switch (rl) { | 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 | else => { | 6701 | else => { |
| 6705 | const result = try gz.addStrTok(.decl_val, name_str_index, ident_token); | 6702 | const result = try gz.addStrTok(.decl_val, name_str_index, ident_token); |
| 6706 | return rvalue(gz, rl, result, ident); | 6703 | return rvalue(gz, rl, result, ident); |
| ... | @@ -7105,7 +7102,7 @@ fn as( | ... | @@ -7105,7 +7102,7 @@ fn as( |
| 7105 | ) InnerError!Zir.Inst.Ref { | 7102 | ) InnerError!Zir.Inst.Ref { |
| 7106 | const dest_type = try typeExpr(gz, scope, lhs); | 7103 | const dest_type = try typeExpr(gz, scope, lhs); |
| 7107 | switch (rl) { | 7104 | switch (rl) { |
| 7108 | .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty => { | 7105 | .none, .discard, .ref, .ty, .coerced_ty => { |
| 7109 | const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node); | 7106 | const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node); |
| 7110 | return rvalue(gz, rl, result, node); | 7107 | return rvalue(gz, rl, result, node); |
| 7111 | }, | 7108 | }, |
| ... | @@ -7128,7 +7125,7 @@ fn unionInit( | ... | @@ -7128,7 +7125,7 @@ fn unionInit( |
| 7128 | const union_type = try typeExpr(gz, scope, params[0]); | 7125 | const union_type = try typeExpr(gz, scope, params[0]); |
| 7129 | const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); | 7126 | const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); |
| 7130 | switch (rl) { | 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 | _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{ | 7129 | _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{ |
| 7133 | .container_type = union_type, | 7130 | .container_type = union_type, |
| 7134 | .field_name = field_name, | 7131 | .field_name = field_name, |
| ... | @@ -7192,7 +7189,7 @@ fn bitCast( | ... | @@ -7192,7 +7189,7 @@ fn bitCast( |
| 7192 | const astgen = gz.astgen; | 7189 | const astgen = gz.astgen; |
| 7193 | const dest_type = try typeExpr(gz, scope, lhs); | 7190 | const dest_type = try typeExpr(gz, scope, lhs); |
| 7194 | switch (rl) { | 7191 | switch (rl) { |
| 7195 | .none, .none_or_ref, .discard, .ty, .coerced_ty => { | 7192 | .none, .discard, .ty, .coerced_ty => { |
| 7196 | const operand = try expr(gz, scope, .none, rhs); | 7193 | const operand = try expr(gz, scope, .none, rhs); |
| 7197 | const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{ | 7194 | const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{ |
| 7198 | .lhs = dest_type, | 7195 | .lhs = dest_type, |
| ... | @@ -8799,7 +8796,7 @@ fn rvalue( | ... | @@ -8799,7 +8796,7 @@ fn rvalue( |
| 8799 | ) InnerError!Zir.Inst.Ref { | 8796 | ) InnerError!Zir.Inst.Ref { |
| 8800 | if (gz.endsWithNoReturn()) return result; | 8797 | if (gz.endsWithNoReturn()) return result; |
| 8801 | switch (rl) { | 8798 | switch (rl) { |
| 8802 | .none, .none_or_ref, .coerced_ty => return result, | 8799 | .none, .coerced_ty => return result, |
| 8803 | .discard => { | 8800 | .discard => { |
| 8804 | // Emit a compile error for discarding error values. | 8801 | // Emit a compile error for discarding error values. |
| 8805 | _ = try gz.addUnNode(.ensure_result_non_error, result, src_node); | 8802 | _ = try gz.addUnNode(.ensure_result_non_error, result, src_node); |
| ... | @@ -9561,9 +9558,7 @@ const GenZir = struct { | ... | @@ -9561,9 +9558,7 @@ const GenZir = struct { |
| 9561 | gz.rl_ty_inst = ty_inst; | 9558 | gz.rl_ty_inst = ty_inst; |
| 9562 | gz.break_result_loc = parent_rl; | 9559 | gz.break_result_loc = parent_rl; |
| 9563 | }, | 9560 | }, |
| 9564 | .none_or_ref => { | 9561 | |
| 9565 | gz.break_result_loc = .ref; | ||
| 9566 | }, | ||
| 9567 | .discard, .none, .ptr, .ref => { | 9562 | .discard, .none, .ptr, .ref => { |
| 9568 | gz.break_result_loc = parent_rl; | 9563 | gz.break_result_loc = parent_rl; |
| 9569 | }, | 9564 | }, |
src/Liveness.zig+2| ... | @@ -300,6 +300,8 @@ fn analyzeInst( | ... | @@ -300,6 +300,8 @@ fn analyzeInst( |
| 300 | .wrap_errunion_err, | 300 | .wrap_errunion_err, |
| 301 | .slice_ptr, | 301 | .slice_ptr, |
| 302 | .slice_len, | 302 | .slice_len, |
| 303 | .ptr_slice_len_ptr, | ||
| 304 | .ptr_slice_ptr_ptr, | ||
| 303 | .struct_field_ptr_index_0, | 305 | .struct_field_ptr_index_0, |
| 304 | .struct_field_ptr_index_1, | 306 | .struct_field_ptr_index_1, |
| 305 | .struct_field_ptr_index_2, | 307 | .struct_field_ptr_index_2, |
src/Sema.zig+291-234| ... | @@ -300,7 +300,7 @@ pub const Block = struct { | ... | @@ -300,7 +300,7 @@ pub const Block = struct { |
| 300 | .ty = ty, | 300 | .ty = ty, |
| 301 | .payload = try block.sema.addExtra(Air.StructField{ | 301 | .payload = try block.sema.addExtra(Air.StructField{ |
| 302 | .struct_operand = struct_ptr, | 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,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 | pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref { | 336 | pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref { |
| 319 | return Air.indexToRef(try block.addInstAsIndex(inst)); | 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,44 +1986,38 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1968 | 1986 | ||
| 1969 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 1987 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 1970 | const src = inst_data.src(); | 1988 | const src = inst_data.src(); |
| 1971 | const array = sema.resolveInst(inst_data.operand); | 1989 | const object = sema.resolveInst(inst_data.operand); |
| 1972 | const array_ty = sema.typeOf(array); | 1990 | const object_ty = sema.typeOf(object); |
| 1973 | 1991 | ||
| 1974 | if (array_ty.isSlice()) { | 1992 | const is_pointer_to = object_ty.isSinglePointer(); |
| 1975 | return sema.analyzeSliceLen(block, src, array); | ||
| 1976 | } | ||
| 1977 | 1993 | ||
| 1978 | if (array_ty.isSinglePointer()) { | 1994 | const array_ty = if (is_pointer_to) |
| 1979 | const elem_ty = array_ty.elemType(); | 1995 | object_ty.childType() |
| 1980 | if (elem_ty.isSlice()) { | 1996 | else |
| 1981 | const slice_inst = try sema.analyzeLoad(block, src, array, src); | 1997 | object_ty; |
| 1982 | return sema.analyzeSliceLen(block, src, slice_inst); | 1998 | |
| 1983 | } | 1999 | if (!array_ty.isIndexable()) { |
| 1984 | if (!elem_ty.isIndexable()) { | 2000 | const msg = msg: { |
| 1985 | const msg = msg: { | 2001 | const msg = try sema.errMsg( |
| 1986 | const msg = try sema.errMsg( | 2002 | block, |
| 1987 | block, | 2003 | src, |
| 1988 | src, | 2004 | "type '{}' does not support indexing", |
| 1989 | "type '{}' does not support indexing", | 2005 | .{array_ty}, |
| 1990 | .{elem_ty}, | 2006 | ); |
| 1991 | ); | 2007 | errdefer msg.destroy(sema.gpa); |
| 1992 | errdefer msg.destroy(sema.gpa); | 2008 | try sema.errNote( |
| 1993 | try sema.errNote( | 2009 | block, |
| 1994 | block, | 2010 | src, |
| 1995 | src, | 2011 | msg, |
| 1996 | msg, | 2012 | "for loop operand must be an array, slice, tuple, or vector", |
| 1997 | "for loop operand must be an array, slice, tuple, or vector", | 2013 | .{}, |
| 1998 | .{}, | 2014 | ); |
| 1999 | ); | 2015 | break :msg msg; |
| 2000 | break :msg msg; | 2016 | }; |
| 2001 | }; | 2017 | return sema.failWithOwnedErrorMsg(msg); |
| 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); | ||
| 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 | fn zirAllocExtended( | 2023 | fn zirAllocExtended( |
| ... | @@ -2304,7 +2316,7 @@ fn validateStructInit( | ... | @@ -2304,7 +2316,7 @@ fn validateStructInit( |
| 2304 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; | 2316 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; |
| 2305 | const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); | 2317 | const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); |
| 2306 | const field_index = struct_obj.fields.getIndex(field_name) orelse | 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 | if (found_fields[field_index] != 0) { | 2320 | if (found_fields[field_index] != 0) { |
| 2309 | const other_field_ptr = found_fields[field_index]; | 2321 | const other_field_ptr = found_fields[field_index]; |
| 2310 | const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node; | 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,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 | sema: *Sema, | 2407 | sema: *Sema, |
| 2371 | block: *Block, | 2408 | block: *Block, |
| 2372 | struct_obj: *Module.Struct, | 2409 | struct_obj: *Module.Struct, |
| ... | @@ -5119,16 +5156,10 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -5119,16 +5156,10 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 5119 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 5156 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 5120 | const src = inst_data.src(); | 5157 | const src = inst_data.src(); |
| 5121 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; | 5158 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; |
| 5122 | const lhs_src: LazySrcLoc = src; // TODO | ||
| 5123 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; | 5159 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; |
| 5124 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); | 5160 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); |
| 5125 | const object = sema.resolveInst(extra.lhs); | 5161 | const object = sema.resolveInst(extra.lhs); |
| 5126 | if (sema.typeOf(object).isSinglePointer()) { | 5162 | return sema.fieldVal(block, src, object, field_name, field_name_src); |
| 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 | } | ||
| 5132 | } | 5163 | } |
| 5133 | 5164 | ||
| 5134 | fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 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,7 +8853,7 @@ fn zirStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) |
| 8822 | const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; | 8853 | const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; |
| 8823 | const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); | 8854 | const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); |
| 8824 | const field_index = struct_obj.fields.getIndex(field_name) orelse | 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 | if (found_fields[field_index] != 0) { | 8857 | if (found_fields[field_index] != 0) { |
| 8827 | const other_field_type = found_fields[field_index]; | 8858 | const other_field_type = found_fields[field_index]; |
| 8828 | const other_field_type_data = zir_datas[other_field_type].pl_node; | 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,7 +9062,7 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 9031 | .Struct => { | 9062 | .Struct => { |
| 9032 | const struct_obj = resolved_ty.castTag(.@"struct").?.data; | 9063 | const struct_obj = resolved_ty.castTag(.@"struct").?.data; |
| 9033 | const field = struct_obj.fields.get(field_name) orelse | 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 | return sema.addType(field.ty); | 9066 | return sema.addType(field.ty); |
| 9036 | }, | 9067 | }, |
| 9037 | .Union => { | 9068 | .Union => { |
| ... | @@ -9331,7 +9362,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -9331,7 +9362,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 9331 | const dest_info = dest_ty.intInfo(target); | 9362 | const dest_info = dest_ty.intInfo(target); |
| 9332 | 9363 | ||
| 9333 | if (src_info.bits == 0 or dest_info.bits == 0) { | 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 | if (!src_is_comptime_int) { | 9368 | if (!src_is_comptime_int) { |
| ... | @@ -10688,12 +10719,22 @@ fn fieldVal( | ... | @@ -10688,12 +10719,22 @@ fn fieldVal( |
| 10688 | const object_src = src; // TODO better source location | 10719 | const object_src = src; // TODO better source location |
| 10689 | const object_ty = sema.typeOf(object); | 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 | .Array => { | 10733 | .Array => { |
| 10693 | if (mem.eql(u8, field_name, "len")) { | 10734 | if (mem.eql(u8, field_name, "len")) { |
| 10694 | return sema.addConstant( | 10735 | return sema.addConstant( |
| 10695 | Type.initTag(.comptime_int), | 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 | } else { | 10739 | } else { |
| 10699 | return sema.fail( | 10740 | return sema.fail( |
| ... | @@ -10704,75 +10745,60 @@ fn fieldVal( | ... | @@ -10704,75 +10745,60 @@ fn fieldVal( |
| 10704 | ); | 10745 | ); |
| 10705 | } | 10746 | } |
| 10706 | }, | 10747 | }, |
| 10707 | .Pointer => switch (object_ty.ptrSize()) { | 10748 | .Pointer => if (inner_ty.isSlice()) { |
| 10708 | .Slice => { | 10749 | if (mem.eql(u8, field_name, "ptr")) { |
| 10709 | if (mem.eql(u8, field_name, "ptr")) { | 10750 | const slice = if (is_pointer_to) |
| 10710 | const buf = try arena.create(Type.SlicePtrFieldTypeBuffer); | 10751 | try sema.analyzeLoad(block, src, object, object_src) |
| 10711 | const result_ty = object_ty.slicePtrFieldType(buf); | 10752 | else |
| 10712 | if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| { | 10753 | object; |
| 10713 | if (val.isUndef()) return sema.addConstUndef(result_ty); | 10754 | |
| 10714 | return sema.addConstant(result_ty, val.slicePtr()); | 10755 | const buf = try arena.create(Type.SlicePtrFieldTypeBuffer); |
| 10715 | } | 10756 | const result_ty = inner_ty.slicePtrFieldType(buf); |
| 10716 | try sema.requireRuntimeBlock(block, src); | 10757 | |
| 10717 | return block.addTyOp(.slice_ptr, result_ty, object); | 10758 | if (try sema.resolveMaybeUndefVal(block, object_src, slice)) |val| { |
| 10718 | } else if (mem.eql(u8, field_name, "len")) { | 10759 | if (val.isUndef()) return sema.addConstUndef(result_ty); |
| 10719 | const result_ty = Type.usize; | 10760 | return sema.addConstant(result_ty, val.slicePtr()); |
| 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 | ); | ||
| 10736 | } | 10761 | } |
| 10737 | }, | 10762 | try sema.requireRuntimeBlock(block, src); |
| 10738 | .One => { | 10763 | return block.addTyOp(.slice_ptr, result_ty, slice); |
| 10739 | const ptr_child = object_ty.elemType(); | 10764 | } else if (mem.eql(u8, field_name, "len")) { |
| 10740 | switch (ptr_child.zigTypeTag()) { | 10765 | const slice = if (is_pointer_to) |
| 10741 | .Array => { | 10766 | try sema.analyzeLoad(block, src, object, object_src) |
| 10742 | if (mem.eql(u8, field_name, "len")) { | 10767 | else |
| 10743 | return sema.addConstant( | 10768 | object; |
| 10744 | Type.initTag(.comptime_int), | 10769 | |
| 10745 | try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()), | 10770 | const result_ty = Type.usize; |
| 10746 | ); | 10771 | |
| 10747 | } else { | 10772 | if (try sema.resolveMaybeUndefVal(block, object_src, slice)) |val| { |
| 10748 | return sema.fail( | 10773 | if (val.isUndef()) return sema.addConstUndef(result_ty); |
| 10749 | block, | 10774 | return sema.addConstant( |
| 10750 | field_name_src, | 10775 | result_ty, |
| 10751 | "no member named '{s}' in '{}'", | 10776 | try Value.Tag.int_u64.create(arena, val.sliceLen()), |
| 10752 | .{ field_name, object_ty }, | 10777 | ); |
| 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 => {}, | ||
| 10765 | } | 10778 | } |
| 10766 | }, | 10779 | try sema.requireRuntimeBlock(block, src); |
| 10767 | .Many, .C => {}, | 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 | .Type => { | 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 | var to_type_buffer: Value.ToTypeBuffer = undefined; | 10797 | var to_type_buffer: Value.ToTypeBuffer = undefined; |
| 10772 | const child_type = val.toType(&to_type_buffer); | 10798 | const child_type = val.toType(&to_type_buffer); |
| 10799 | |||
| 10773 | switch (child_type.zigTypeTag()) { | 10800 | switch (child_type.zigTypeTag()) { |
| 10774 | .ErrorSet => { | 10801 | .ErrorSet => { |
| 10775 | // TODO resolve inferred error sets | ||
| 10776 | const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: { | 10802 | const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: { |
| 10777 | const error_set = payload.data; | 10803 | const error_set = payload.data; |
| 10778 | // TODO this is O(N). I'm putting off solving this until we solve inferred | 10804 | // TODO this is O(N). I'm putting off solving this until we solve inferred |
| ... | @@ -10842,8 +10868,20 @@ fn fieldVal( | ... | @@ -10842,8 +10868,20 @@ fn fieldVal( |
| 10842 | else => return sema.fail(block, src, "type '{}' has no members", .{child_type}), | 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), | 10871 | .Struct => if (is_pointer_to) { |
| 10846 | .Union => return sema.unionFieldVal(block, src, object, field_name, field_name_src, object_ty), | 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 | else => {}, | 10885 | else => {}, |
| 10848 | } | 10886 | } |
| 10849 | return sema.fail(block, src, "type '{}' does not support field access", .{object_ty}); | 10887 | return sema.fail(block, src, "type '{}' does not support field access", .{object_ty}); |
| ... | @@ -10866,14 +10904,25 @@ fn fieldPtr( | ... | @@ -10866,14 +10904,25 @@ fn fieldPtr( |
| 10866 | .Pointer => object_ptr_ty.elemType(), | 10904 | .Pointer => object_ptr_ty.elemType(), |
| 10867 | else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty}), | 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 | .Array => { | 10919 | .Array => { |
| 10871 | if (mem.eql(u8, field_name, "len")) { | 10920 | if (mem.eql(u8, field_name, "len")) { |
| 10872 | var anon_decl = try block.startAnonDecl(); | 10921 | var anon_decl = try block.startAnonDecl(); |
| 10873 | defer anon_decl.deinit(); | 10922 | defer anon_decl.deinit(); |
| 10874 | return sema.analyzeDeclRef(try anon_decl.finish( | 10923 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 10875 | Type.initTag(.comptime_int), | 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 | } else { | 10927 | } else { |
| 10879 | return sema.fail( | 10928 | return sema.fail( |
| ... | @@ -10884,77 +10933,74 @@ fn fieldPtr( | ... | @@ -10884,77 +10933,74 @@ fn fieldPtr( |
| 10884 | ); | 10933 | ); |
| 10885 | } | 10934 | } |
| 10886 | }, | 10935 | }, |
| 10887 | .Pointer => switch (object_ty.ptrSize()) { | 10936 | .Pointer => if (inner_ty.isSlice()) { |
| 10888 | .Slice => { | 10937 | const inner_ptr = if (is_pointer_to) |
| 10889 | // Here for the ptr and len fields what we need to do is the situation | 10938 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) |
| 10890 | // when a temporary has its address taken, e.g. `&a[c..d].len`. | 10939 | else |
| 10891 | // This value may be known at compile-time or runtime. In the former | 10940 | object_ptr; |
| 10892 | // case, it should create an anonymous Decl and return a decl_ref to it. | 10941 | |
| 10893 | // In the latter case, it should add an `alloc` instruction, store | 10942 | if (mem.eql(u8, field_name, "ptr")) { |
| 10894 | // the runtime value to it, and then return the `alloc`. | 10943 | const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer); |
| 10895 | // In both cases the pointer should be const. | 10944 | const slice_ptr_ty = inner_ty.slicePtrFieldType(buf); |
| 10896 | if (mem.eql(u8, field_name, "ptr")) { | 10945 | |
| 10897 | return sema.fail( | 10946 | if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { |
| 10898 | block, | 10947 | var anon_decl = try block.startAnonDecl(); |
| 10899 | field_name_src, | 10948 | defer anon_decl.deinit(); |
| 10900 | "TODO: implement reference to 'ptr' field of slice '{}'", | 10949 | |
| 10901 | .{object_ty}, | 10950 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 10902 | ); | 10951 | try slice_ptr_ty.copy(anon_decl.arena()), |
| 10903 | } else if (mem.eql(u8, field_name, "len")) { | 10952 | try val.slicePtr().copy(anon_decl.arena()), |
| 10904 | return sema.fail( | 10953 | )); |
| 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 | ); | ||
| 10917 | } | 10954 | } |
| 10918 | }, | 10955 | try sema.requireRuntimeBlock(block, src); |
| 10919 | .One => { | 10956 | |
| 10920 | const ptr_child = object_ty.elemType(); | 10957 | const result_ty = try Type.ptr(sema.arena, .{ |
| 10921 | switch (ptr_child.zigTypeTag()) { | 10958 | .pointee_type = slice_ptr_ty, |
| 10922 | .Array => { | 10959 | .mutable = object_ptr_ty.ptrIsMutable(), |
| 10923 | if (mem.eql(u8, field_name, "len")) { | 10960 | .@"addrspace" = object_ptr_ty.ptrAddressSpace(), |
| 10924 | var anon_decl = try block.startAnonDecl(); | 10961 | }); |
| 10925 | defer anon_decl.deinit(); | 10962 | |
| 10926 | return sema.analyzeDeclRef(try anon_decl.finish( | 10963 | return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr); |
| 10927 | Type.initTag(.comptime_int), | 10964 | } else if (mem.eql(u8, field_name, "len")) { |
| 10928 | try Value.Tag.int_u64.create(anon_decl.arena(), ptr_child.arrayLen()), | 10965 | if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { |
| 10929 | )); | 10966 | var anon_decl = try block.startAnonDecl(); |
| 10930 | } else { | 10967 | defer anon_decl.deinit(); |
| 10931 | return sema.fail( | 10968 | |
| 10932 | block, | 10969 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 10933 | field_name_src, | 10970 | Type.usize, |
| 10934 | "no member named '{s}' in '{}'", | 10971 | try Value.Tag.int_u64.create(anon_decl.arena(), val.sliceLen()), |
| 10935 | .{ field_name, object_ty }, | 10972 | )); |
| 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 => {}, | ||
| 10948 | } | 10973 | } |
| 10949 | }, | 10974 | try sema.requireRuntimeBlock(block, src); |
| 10950 | .Many, .C => {}, | 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 | .Type => { | 10992 | .Type => { |
| 10953 | _ = try sema.resolveConstValue(block, object_ptr_src, object_ptr); | 10993 | _ = try sema.resolveConstValue(block, object_ptr_src, object_ptr); |
| 10954 | const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src); | 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 | var to_type_buffer: Value.ToTypeBuffer = undefined; | 11001 | var to_type_buffer: Value.ToTypeBuffer = undefined; |
| 10957 | const child_type = val.toType(&to_type_buffer); | 11002 | const child_type = val.toType(&to_type_buffer); |
| 11003 | |||
| 10958 | switch (child_type.zigTypeTag()) { | 11004 | switch (child_type.zigTypeTag()) { |
| 10959 | .ErrorSet => { | 11005 | .ErrorSet => { |
| 10960 | // TODO resolve inferred error sets | 11006 | // TODO resolve inferred error sets |
| ... | @@ -10980,22 +11026,24 @@ fn fieldPtr( | ... | @@ -10980,22 +11026,24 @@ fn fieldPtr( |
| 10980 | try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }), | 11026 | try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }), |
| 10981 | )); | 11027 | )); |
| 10982 | }, | 11028 | }, |
| 10983 | .Struct, .Opaque, .Union => { | 11029 | .Union => { |
| 10984 | if (child_type.getNamespace()) |namespace| { | 11030 | if (child_type.getNamespace()) |namespace| { |
| 10985 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { | 11031 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { |
| 10986 | return inst; | 11032 | return inst; |
| 10987 | } | 11033 | } |
| 10988 | } | 11034 | } |
| 10989 | // TODO add note: declared here | 11035 | if (child_type.unionTagType()) |enum_ty| { |
| 10990 | const kw_name = switch (child_type.zigTypeTag()) { | 11036 | if (enum_ty.enumFieldIndex(field_name)) |field_index| { |
| 10991 | .Struct => "struct", | 11037 | const field_index_u32 = @intCast(u32, field_index); |
| 10992 | .Opaque => "opaque", | 11038 | var anon_decl = try block.startAnonDecl(); |
| 10993 | .Union => "union", | 11039 | defer anon_decl.deinit(); |
| 10994 | else => unreachable, | 11040 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 10995 | }; | 11041 | try enum_ty.copy(anon_decl.arena()), |
| 10996 | return sema.fail(block, src, "{s} '{}' has no member named '{s}'", .{ | 11042 | try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32), |
| 10997 | kw_name, child_type, field_name, | 11043 | )); |
| 10998 | }); | 11044 | } |
| 11045 | } | ||
| 11046 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); | ||
| 10999 | }, | 11047 | }, |
| 11000 | .Enum => { | 11048 | .Enum => { |
| 11001 | if (child_type.getNamespace()) |namespace| { | 11049 | if (child_type.getNamespace()) |namespace| { |
| ... | @@ -11004,23 +11052,7 @@ fn fieldPtr( | ... | @@ -11004,23 +11052,7 @@ fn fieldPtr( |
| 11004 | } | 11052 | } |
| 11005 | } | 11053 | } |
| 11006 | const field_index = child_type.enumFieldIndex(field_name) orelse { | 11054 | const field_index = child_type.enumFieldIndex(field_name) orelse { |
| 11007 | const msg = msg: { | 11055 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| 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); | ||
| 11024 | }; | 11056 | }; |
| 11025 | const field_index_u32 = @intCast(u32, field_index); | 11057 | const field_index_u32 = @intCast(u32, field_index); |
| 11026 | var anon_decl = try block.startAnonDecl(); | 11058 | var anon_decl = try block.startAnonDecl(); |
| ... | @@ -11030,14 +11062,34 @@ fn fieldPtr( | ... | @@ -11030,14 +11062,34 @@ fn fieldPtr( |
| 11030 | try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32), | 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 | else => return sema.fail(block, src, "type '{}' has no members", .{child_type}), | 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), | 11076 | .Struct => { |
| 11037 | .Union => return sema.unionFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty), | 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 | else => {}, | 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 | fn fieldCallBind( | 11095 | fn fieldCallBind( |
| ... | @@ -11209,7 +11261,7 @@ fn structFieldPtr( | ... | @@ -11209,7 +11261,7 @@ fn structFieldPtr( |
| 11209 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 11261 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| 11210 | 11262 | ||
| 11211 | const field_index_big = struct_obj.fields.getIndex(field_name) orelse | 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 | const field_index = @intCast(u32, field_index_big); | 11265 | const field_index = @intCast(u32, field_index_big); |
| 11214 | const field = struct_obj.fields.values()[field_index]; | 11266 | const field = struct_obj.fields.values()[field_index]; |
| 11215 | const ptr_field_ty = try Type.ptr(arena, .{ | 11267 | const ptr_field_ty = try Type.ptr(arena, .{ |
| ... | @@ -11246,8 +11298,9 @@ fn structFieldVal( | ... | @@ -11246,8 +11298,9 @@ fn structFieldVal( |
| 11246 | const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty); | 11298 | const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty); |
| 11247 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 11299 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| 11248 | 11300 | ||
| 11249 | const field_index = struct_obj.fields.getIndex(field_name) orelse | 11301 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse |
| 11250 | return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name); | 11302 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); |
| 11303 | const field_index = @intCast(u32, field_index_usize); | ||
| 11251 | const field = struct_obj.fields.values()[field_index]; | 11304 | const field = struct_obj.fields.values()[field_index]; |
| 11252 | 11305 | ||
| 11253 | if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| { | 11306 | if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| { |
| ... | @@ -11258,16 +11311,7 @@ fn structFieldVal( | ... | @@ -11258,16 +11311,7 @@ fn structFieldVal( |
| 11258 | } | 11311 | } |
| 11259 | 11312 | ||
| 11260 | try sema.requireRuntimeBlock(block, src); | 11313 | try sema.requireRuntimeBlock(block, src); |
| 11261 | return block.addInst(.{ | 11314 | return block.addStructFieldVal(struct_byval, field_index, field.ty); |
| 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 | }); | ||
| 11271 | } | 11315 | } |
| 11272 | 11316 | ||
| 11273 | fn unionFieldPtr( | 11317 | fn unionFieldPtr( |
| ... | @@ -11326,8 +11370,9 @@ fn unionFieldVal( | ... | @@ -11326,8 +11370,9 @@ fn unionFieldVal( |
| 11326 | const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty); | 11370 | const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty); |
| 11327 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | 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 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name); | 11374 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name); |
| 11375 | const field_index = @intCast(u32, field_index_big); | ||
| 11331 | 11376 | ||
| 11332 | const field = union_obj.fields.values()[field_index]; | 11377 | const field = union_obj.fields.values()[field_index]; |
| 11333 | 11378 | ||
| ... | @@ -11340,7 +11385,7 @@ fn unionFieldVal( | ... | @@ -11340,7 +11385,7 @@ fn unionFieldVal( |
| 11340 | } | 11385 | } |
| 11341 | 11386 | ||
| 11342 | try sema.requireRuntimeBlock(block, src); | 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 | fn elemPtr( | 11391 | fn elemPtr( |
| ... | @@ -13141,6 +13186,10 @@ pub fn resolveTypeLayout( | ... | @@ -13141,6 +13186,10 @@ pub fn resolveTypeLayout( |
| 13141 | } | 13186 | } |
| 13142 | union_obj.status = .have_layout; | 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 | else => {}, | 13193 | else => {}, |
| 13145 | } | 13194 | } |
| 13146 | } | 13195 | } |
| ... | @@ -13693,10 +13742,9 @@ fn typeHasOnePossibleValue( | ... | @@ -13693,10 +13742,9 @@ fn typeHasOnePossibleValue( |
| 13693 | sema: *Sema, | 13742 | sema: *Sema, |
| 13694 | block: *Block, | 13743 | block: *Block, |
| 13695 | src: LazySrcLoc, | 13744 | src: LazySrcLoc, |
| 13696 | starting_type: Type, | 13745 | ty: Type, |
| 13697 | ) CompileError!?Value { | 13746 | ) CompileError!?Value { |
| 13698 | var ty = starting_type; | 13747 | switch (ty.tag()) { |
| 13699 | while (true) switch (ty.tag()) { | ||
| 13700 | .f16, | 13748 | .f16, |
| 13701 | .f32, | 13749 | .f32, |
| 13702 | .f64, | 13750 | .f64, |
| ... | @@ -13790,7 +13838,7 @@ fn typeHasOnePossibleValue( | ... | @@ -13790,7 +13838,7 @@ fn typeHasOnePossibleValue( |
| 13790 | const enum_obj = resolved_ty.castTag(.enum_numbered).?.data; | 13838 | const enum_obj = resolved_ty.castTag(.enum_numbered).?.data; |
| 13791 | if (enum_obj.fields.count() == 1) { | 13839 | if (enum_obj.fields.count() == 1) { |
| 13792 | if (enum_obj.values.count() == 0) { | 13840 | if (enum_obj.values.count() == 0) { |
| 13793 | return Value.initTag(.zero); // auto-numbered | 13841 | return Value.zero; // auto-numbered |
| 13794 | } else { | 13842 | } else { |
| 13795 | return enum_obj.values.keys()[0]; | 13843 | return enum_obj.values.keys()[0]; |
| 13796 | } | 13844 | } |
| ... | @@ -13803,7 +13851,7 @@ fn typeHasOnePossibleValue( | ... | @@ -13803,7 +13851,7 @@ fn typeHasOnePossibleValue( |
| 13803 | const enum_obj = resolved_ty.castTag(.enum_full).?.data; | 13851 | const enum_obj = resolved_ty.castTag(.enum_full).?.data; |
| 13804 | if (enum_obj.fields.count() == 1) { | 13852 | if (enum_obj.fields.count() == 1) { |
| 13805 | if (enum_obj.values.count() == 0) { | 13853 | if (enum_obj.values.count() == 0) { |
| 13806 | return Value.initTag(.zero); // auto-numbered | 13854 | return Value.zero; // auto-numbered |
| 13807 | } else { | 13855 | } else { |
| 13808 | return enum_obj.values.keys()[0]; | 13856 | return enum_obj.values.keys()[0]; |
| 13809 | } | 13857 | } |
| ... | @@ -13815,12 +13863,19 @@ fn typeHasOnePossibleValue( | ... | @@ -13815,12 +13863,19 @@ fn typeHasOnePossibleValue( |
| 13815 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); | 13863 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); |
| 13816 | const enum_simple = resolved_ty.castTag(.enum_simple).?.data; | 13864 | const enum_simple = resolved_ty.castTag(.enum_simple).?.data; |
| 13817 | if (enum_simple.fields.count() == 1) { | 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 | } else { | 13875 | } else { |
| 13820 | return null; | 13876 | return null; |
| 13821 | } | 13877 | } |
| 13822 | }, | 13878 | }, |
| 13823 | .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty, | ||
| 13824 | .@"union" => { | 13879 | .@"union" => { |
| 13825 | return null; // TODO | 13880 | return null; // TODO |
| 13826 | }, | 13881 | }, |
| ... | @@ -13836,7 +13891,7 @@ fn typeHasOnePossibleValue( | ... | @@ -13836,7 +13891,7 @@ fn typeHasOnePossibleValue( |
| 13836 | 13891 | ||
| 13837 | .int_unsigned, .int_signed => { | 13892 | .int_unsigned, .int_signed => { |
| 13838 | if (ty.cast(Type.Payload.Bits).?.data == 0) { | 13893 | if (ty.cast(Type.Payload.Bits).?.data == 0) { |
| 13839 | return Value.initTag(.zero); | 13894 | return Value.zero; |
| 13840 | } else { | 13895 | } else { |
| 13841 | return null; | 13896 | return null; |
| 13842 | } | 13897 | } |
| ... | @@ -13844,14 +13899,16 @@ fn typeHasOnePossibleValue( | ... | @@ -13844,14 +13899,16 @@ fn typeHasOnePossibleValue( |
| 13844 | .vector, .array, .array_u8 => { | 13899 | .vector, .array, .array_u8 => { |
| 13845 | if (ty.arrayLen() == 0) | 13900 | if (ty.arrayLen() == 0) |
| 13846 | return Value.initTag(.empty_array); | 13901 | return Value.initTag(.empty_array); |
| 13847 | ty = ty.elemType(); | 13902 | if ((try sema.typeHasOnePossibleValue(block, src, ty.elemType())) != null) { |
| 13848 | continue; | 13903 | return Value.initTag(.the_only_possible_value); |
| 13904 | } | ||
| 13905 | return null; | ||
| 13849 | }, | 13906 | }, |
| 13850 | 13907 | ||
| 13851 | .inferred_alloc_const => unreachable, | 13908 | .inferred_alloc_const => unreachable, |
| 13852 | .inferred_alloc_mut => unreachable, | 13909 | .inferred_alloc_mut => unreachable, |
| 13853 | .generic_poison => return error.GenericPoison, | 13910 | .generic_poison => return error.GenericPoison, |
| 13854 | }; | 13911 | } |
| 13855 | } | 13912 | } |
| 13856 | 13913 | ||
| 13857 | fn getAstTree(sema: *Sema, block: *Block) CompileError!*const std.zig.Ast { | 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,6 +494,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 494 | .slice_ptr => try self.airSlicePtr(inst), | 494 | .slice_ptr => try self.airSlicePtr(inst), |
| 495 | .slice_len => try self.airSliceLen(inst), | 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 | .array_elem_val => try self.airArrayElemVal(inst), | 500 | .array_elem_val => try self.airArrayElemVal(inst), |
| 498 | .slice_elem_val => try self.airSliceElemVal(inst), | 501 | .slice_elem_val => try self.airSliceElemVal(inst), |
| 499 | .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst), | 502 | .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst), |
| ... | @@ -1057,6 +1060,18 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1057,6 +1060,18 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1057 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | 1075 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1061 | const is_volatile = false; // TODO | 1076 | const is_volatile = false; // TODO |
| 1062 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 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,6 +842,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 842 | .slice_ptr => try self.airSlicePtr(inst), | 842 | .slice_ptr => try self.airSlicePtr(inst), |
| 843 | .slice_len => try self.airSliceLen(inst), | 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 | .array_elem_val => try self.airArrayElemVal(inst), | 848 | .array_elem_val => try self.airArrayElemVal(inst), |
| 846 | .slice_elem_val => try self.airSliceElemVal(inst), | 849 | .slice_elem_val => try self.airSliceElemVal(inst), |
| 847 | .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst), | 850 | .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst), |
| ... | @@ -1498,6 +1501,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1498,6 +1501,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1498 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | 1520 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1502 | const is_volatile = false; // TODO | 1521 | const is_volatile = false; // TODO |
| 1503 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 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,6 +1075,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1075 | .slice_ptr => try airSliceField(f, inst, ".ptr;\n"), | 1075 | .slice_ptr => try airSliceField(f, inst, ".ptr;\n"), |
| 1076 | .slice_len => try airSliceField(f, inst, ".len;\n"), | 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 | .ptr_elem_val => try airPtrElemVal(f, inst, "["), | 1081 | .ptr_elem_val => try airPtrElemVal(f, inst, "["), |
| 1079 | .ptr_ptr_elem_val => try airPtrElemVal(f, inst, "[0]["), | 1082 | .ptr_ptr_elem_val => try airPtrElemVal(f, inst, "[0]["), |
| 1080 | .ptr_elem_ptr => try airPtrElemPtr(f, inst), | 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,6 +1117,21 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue |
| 1114 | return local; | 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 | fn airPtrElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue { | 1135 | fn airPtrElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue { |
| 1118 | const is_volatile = false; // TODO | 1136 | const is_volatile = false; // TODO |
| 1119 | if (!is_volatile and f.liveness.isUnused(inst)) | 1137 | if (!is_volatile and f.liveness.isUnused(inst)) |
src/codegen/llvm.zig+44-10| ... | @@ -1261,6 +1261,10 @@ pub const DeclGen = struct { | ... | @@ -1261,6 +1261,10 @@ pub const DeclGen = struct { |
| 1261 | } | 1261 | } |
| 1262 | const field_ty = tv.ty.unionFieldType(tag_and_val.tag); | 1262 | const field_ty = tv.ty.unionFieldType(tag_and_val.tag); |
| 1263 | const payload = p: { | 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 | const field = try genTypedValue(self, .{ .ty = field_ty, .val = tag_and_val.val }); | 1268 | const field = try genTypedValue(self, .{ .ty = field_ty, .val = tag_and_val.val }); |
| 1265 | const field_size = field_ty.abiSize(target); | 1269 | const field_size = field_ty.abiSize(target); |
| 1266 | if (field_size == layout.payload_size) { | 1270 | if (field_size == layout.payload_size) { |
| ... | @@ -1709,6 +1713,10 @@ pub const FuncGen = struct { | ... | @@ -1709,6 +1713,10 @@ pub const FuncGen = struct { |
| 1709 | .assembly => try self.airAssembly(inst), | 1713 | .assembly => try self.airAssembly(inst), |
| 1710 | .slice_ptr => try self.airSliceField(inst, 0), | 1714 | .slice_ptr => try self.airSliceField(inst, 0), |
| 1711 | .slice_len => try self.airSliceField(inst, 1), | 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 | .array_to_slice => try self.airArrayToSlice(inst), | 1720 | .array_to_slice => try self.airArrayToSlice(inst), |
| 1713 | .float_to_int => try self.airFloatToInt(inst), | 1721 | .float_to_int => try self.airFloatToInt(inst), |
| 1714 | .int_to_float => try self.airIntToFloat(inst), | 1722 | .int_to_float => try self.airIntToFloat(inst), |
| ... | @@ -2091,6 +2099,15 @@ pub const FuncGen = struct { | ... | @@ -2091,6 +2099,15 @@ pub const FuncGen = struct { |
| 2091 | return self.builder.buildExtractValue(operand, index, ""); | 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 | fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 2111 | fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 2095 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2112 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2096 | const slice_ty = self.air.typeOf(bin_op.lhs); | 2113 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| ... | @@ -2223,17 +2240,34 @@ pub const FuncGen = struct { | ... | @@ -2223,17 +2240,34 @@ pub const FuncGen = struct { |
| 2223 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; | 2240 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 2224 | const struct_ty = self.air.typeOf(struct_field.struct_operand); | 2241 | const struct_ty = self.air.typeOf(struct_field.struct_operand); |
| 2225 | const struct_llvm_val = try self.resolveInst(struct_field.struct_operand); | 2242 | const struct_llvm_val = try self.resolveInst(struct_field.struct_operand); |
| 2226 | const field_index = llvmFieldIndex(struct_ty, struct_field.field_index); | 2243 | const field_index = struct_field.field_index; |
| 2227 | if (isByRef(struct_ty)) { | 2244 | const field_ty = struct_ty.structFieldType(field_index); |
| 2228 | const field_ptr = self.builder.buildStructGEP(struct_llvm_val, field_index, ""); | 2245 | if (!field_ty.hasCodeGenBits()) { |
| 2229 | const field_ty = struct_ty.structFieldType(struct_field.field_index); | 2246 | return null; |
| 2230 | if (isByRef(field_ty)) { | 2247 | } |
| 2231 | return field_ptr; | 2248 | |
| 2232 | } else { | 2249 | assert(isByRef(struct_ty)); |
| 2233 | return self.builder.buildLoad(field_ptr, ""); | 2250 | |
| 2234 | } | 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 | } else { | 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,6 +866,7 @@ pub const Context = struct { |
| 866 | .struct_field_ptr_index_1 => self.airStructFieldPtrIndex(inst, 1), | 866 | .struct_field_ptr_index_1 => self.airStructFieldPtrIndex(inst, 1), |
| 867 | .struct_field_ptr_index_2 => self.airStructFieldPtrIndex(inst, 2), | 867 | .struct_field_ptr_index_2 => self.airStructFieldPtrIndex(inst, 2), |
| 868 | .struct_field_ptr_index_3 => self.airStructFieldPtrIndex(inst, 3), | 868 | .struct_field_ptr_index_3 => self.airStructFieldPtrIndex(inst, 3), |
| 869 | .struct_field_val => self.airStructFieldVal(inst), | ||
| 869 | .switch_br => self.airSwitchBr(inst), | 870 | .switch_br => self.airSwitchBr(inst), |
| 870 | .unreach => self.airUnreachable(inst), | 871 | .unreach => self.airUnreachable(inst), |
| 871 | .wrap_optional => self.airWrapOptional(inst), | 872 | .wrap_optional => self.airWrapOptional(inst), |
| ... | @@ -1456,6 +1457,15 @@ pub const Context = struct { | ... | @@ -1456,6 +1457,15 @@ pub const Context = struct { |
| 1456 | return WValue{ .local = struct_ptr.multi_value.index + index }; | 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 | fn airSwitchBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue { | 1469 | fn airSwitchBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue { |
| 1460 | // result type is always 'noreturn' | 1470 | // result type is always 'noreturn' |
| 1461 | const blocktype = wasm.block_empty; | 1471 | const blocktype = wasm.block_empty; |
src/print_air.zig+2| ... | @@ -183,6 +183,8 @@ const Writer = struct { | ... | @@ -183,6 +183,8 @@ const Writer = struct { |
| 183 | .wrap_errunion_err, | 183 | .wrap_errunion_err, |
| 184 | .slice_ptr, | 184 | .slice_ptr, |
| 185 | .slice_len, | 185 | .slice_len, |
| 186 | .ptr_slice_len_ptr, | ||
| 187 | .ptr_slice_ptr_ptr, | ||
| 186 | .struct_field_ptr_index_0, | 188 | .struct_field_ptr_index_0, |
| 187 | .struct_field_ptr_index_1, | 189 | .struct_field_ptr_index_1, |
| 188 | .struct_field_ptr_index_2, | 190 | .struct_field_ptr_index_2, |
src/type.zig+24-9| ... | @@ -2676,7 +2676,7 @@ pub const Type = extern union { | ... | @@ -2676,7 +2676,7 @@ pub const Type = extern union { |
| 2676 | 2676 | ||
| 2677 | .pointer => return self.castTag(.pointer).?.data.sentinel, | 2677 | .pointer => return self.castTag(.pointer).?.data.sentinel, |
| 2678 | .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel, | 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 | else => unreachable, | 2681 | else => unreachable, |
| 2682 | }; | 2682 | }; |
| ... | @@ -3096,6 +3096,14 @@ pub const Type = extern union { | ... | @@ -3096,6 +3096,14 @@ pub const Type = extern union { |
| 3096 | } | 3096 | } |
| 3097 | return Value.initTag(.empty_struct_value); | 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 | .enum_full => { | 3107 | .enum_full => { |
| 3100 | const enum_full = ty.castTag(.enum_full).?.data; | 3108 | const enum_full = ty.castTag(.enum_full).?.data; |
| 3101 | if (enum_full.fields.count() == 1) { | 3109 | if (enum_full.fields.count() == 1) { |
| ... | @@ -3107,13 +3115,19 @@ pub const Type = extern union { | ... | @@ -3107,13 +3115,19 @@ pub const Type = extern union { |
| 3107 | .enum_simple => { | 3115 | .enum_simple => { |
| 3108 | const enum_simple = ty.castTag(.enum_simple).?.data; | 3116 | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 3109 | if (enum_simple.fields.count() == 1) { | 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 | } else { | 3127 | } else { |
| 3112 | return null; | 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 | .@"union" => { | 3131 | .@"union" => { |
| 3118 | return null; // TODO | 3132 | return null; // TODO |
| 3119 | }, | 3133 | }, |
| ... | @@ -3129,7 +3143,7 @@ pub const Type = extern union { | ... | @@ -3129,7 +3143,7 @@ pub const Type = extern union { |
| 3129 | 3143 | ||
| 3130 | .int_unsigned, .int_signed => { | 3144 | .int_unsigned, .int_signed => { |
| 3131 | if (ty.cast(Payload.Bits).?.data == 0) { | 3145 | if (ty.cast(Payload.Bits).?.data == 0) { |
| 3132 | return Value.initTag(.zero); | 3146 | return Value.zero; |
| 3133 | } else { | 3147 | } else { |
| 3134 | return null; | 3148 | return null; |
| 3135 | } | 3149 | } |
| ... | @@ -3137,8 +3151,9 @@ pub const Type = extern union { | ... | @@ -3137,8 +3151,9 @@ pub const Type = extern union { |
| 3137 | .vector, .array, .array_u8 => { | 3151 | .vector, .array, .array_u8 => { |
| 3138 | if (ty.arrayLen() == 0) | 3152 | if (ty.arrayLen() == 0) |
| 3139 | return Value.initTag(.empty_array); | 3153 | return Value.initTag(.empty_array); |
| 3140 | ty = ty.elemType(); | 3154 | if (ty.elemType().onePossibleValue() != null) |
| 3141 | continue; | 3155 | return Value.initTag(.the_only_possible_value); |
| 3156 | return null; | ||
| 3142 | }, | 3157 | }, |
| 3143 | 3158 | ||
| 3144 | .inferred_alloc_const => unreachable, | 3159 | .inferred_alloc_const => unreachable, |
| ... | @@ -3179,7 +3194,7 @@ pub const Type = extern union { | ... | @@ -3179,7 +3194,7 @@ pub const Type = extern union { |
| 3179 | const info = self.intInfo(target); | 3194 | const info = self.intInfo(target); |
| 3180 | 3195 | ||
| 3181 | if (info.signedness == .unsigned) { | 3196 | if (info.signedness == .unsigned) { |
| 3182 | return Value.initTag(.zero); | 3197 | return Value.zero; |
| 3183 | } | 3198 | } |
| 3184 | 3199 | ||
| 3185 | if (info.bits <= 6) { | 3200 | if (info.bits <= 6) { |
| ... | @@ -4013,7 +4028,7 @@ pub const Type = extern union { | ... | @@ -4013,7 +4028,7 @@ pub const Type = extern union { |
| 4013 | ) Allocator.Error!Type { | 4028 | ) Allocator.Error!Type { |
| 4014 | if (elem_type.eql(Type.u8)) { | 4029 | if (elem_type.eql(Type.u8)) { |
| 4015 | if (sent) |some| { | 4030 | if (sent) |some| { |
| 4016 | if (some.eql(Value.initTag(.zero), elem_type)) { | 4031 | if (some.eql(Value.zero, elem_type)) { |
| 4017 | return Tag.array_u8_sentinel_0.create(arena, len); | 4032 | return Tag.array_u8_sentinel_0.create(arena, len); |
| 4018 | } | 4033 | } |
| 4019 | } else { | 4034 | } else { |
src/value.zig+74-37| ... | @@ -86,6 +86,8 @@ pub const Value = extern union { | ... | @@ -86,6 +86,8 @@ pub const Value = extern union { |
| 86 | one, | 86 | one, |
| 87 | void_value, | 87 | void_value, |
| 88 | unreachable_value, | 88 | unreachable_value, |
| 89 | /// The only possible value for a particular type, which is stored externally. | ||
| 90 | the_only_possible_value, | ||
| 89 | null_value, | 91 | null_value, |
| 90 | bool_true, | 92 | bool_true, |
| 91 | bool_false, | 93 | bool_false, |
| ... | @@ -226,6 +228,7 @@ pub const Value = extern union { | ... | @@ -226,6 +228,7 @@ pub const Value = extern union { |
| 226 | .one, | 228 | .one, |
| 227 | .void_value, | 229 | .void_value, |
| 228 | .unreachable_value, | 230 | .unreachable_value, |
| 231 | .the_only_possible_value, | ||
| 229 | .empty_struct_value, | 232 | .empty_struct_value, |
| 230 | .empty_array, | 233 | .empty_array, |
| 231 | .null_value, | 234 | .null_value, |
| ... | @@ -415,6 +418,7 @@ pub const Value = extern union { | ... | @@ -415,6 +418,7 @@ pub const Value = extern union { |
| 415 | .one, | 418 | .one, |
| 416 | .void_value, | 419 | .void_value, |
| 417 | .unreachable_value, | 420 | .unreachable_value, |
| 421 | .the_only_possible_value, | ||
| 418 | .empty_array, | 422 | .empty_array, |
| 419 | .null_value, | 423 | .null_value, |
| 420 | .bool_true, | 424 | .bool_true, |
| ... | @@ -664,6 +668,7 @@ pub const Value = extern union { | ... | @@ -664,6 +668,7 @@ pub const Value = extern union { |
| 664 | .one => return out_stream.writeAll("1"), | 668 | .one => return out_stream.writeAll("1"), |
| 665 | .void_value => return out_stream.writeAll("{}"), | 669 | .void_value => return out_stream.writeAll("{}"), |
| 666 | .unreachable_value => return out_stream.writeAll("unreachable"), | 670 | .unreachable_value => return out_stream.writeAll("unreachable"), |
| 671 | .the_only_possible_value => return out_stream.writeAll("(the only possible value)"), | ||
| 667 | .bool_true => return out_stream.writeAll("true"), | 672 | .bool_true => return out_stream.writeAll("true"), |
| 668 | .bool_false => return out_stream.writeAll("false"), | 673 | .bool_false => return out_stream.writeAll("false"), |
| 669 | .ty => return val.castTag(.ty).?.data.format("", options, out_stream), | 674 | .ty => return val.castTag(.ty).?.data.format("", options, out_stream), |
| ... | @@ -755,6 +760,7 @@ pub const Value = extern union { | ... | @@ -755,6 +760,7 @@ pub const Value = extern union { |
| 755 | const decl_val = try decl.value(); | 760 | const decl_val = try decl.value(); |
| 756 | return decl_val.toAllocatedBytes(decl.ty, allocator); | 761 | return decl_val.toAllocatedBytes(decl.ty, allocator); |
| 757 | }, | 762 | }, |
| 763 | .the_only_possible_value => return &[_]u8{}, | ||
| 758 | else => unreachable, | 764 | else => unreachable, |
| 759 | } | 765 | } |
| 760 | } | 766 | } |
| ... | @@ -847,53 +853,63 @@ pub const Value = extern union { | ... | @@ -847,53 +853,63 @@ pub const Value = extern union { |
| 847 | // TODO should `@intToEnum` do this `@intCast` for you? | 853 | // TODO should `@intToEnum` do this `@intCast` for you? |
| 848 | return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index)); | 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 | else => unreachable, | 861 | else => unreachable, |
| 851 | } | 862 | } |
| 852 | } | 863 | } |
| 853 | 864 | ||
| 854 | pub fn enumToInt(val: Value, ty: Type, buffer: *Payload.U64) Value { | 865 | pub fn enumToInt(val: Value, ty: Type, buffer: *Payload.U64) Value { |
| 855 | if (val.castTag(.enum_field_index)) |enum_field_payload| { | 866 | const field_index = switch (val.tag()) { |
| 856 | const field_index = enum_field_payload.data; | 867 | .enum_field_index => val.castTag(.enum_field_index).?.data, |
| 857 | switch (ty.tag()) { | 868 | .the_only_possible_value => blk: { |
| 858 | .enum_full, .enum_nonexhaustive => { | 869 | assert(ty.enumFieldCount() == 1); |
| 859 | const enum_full = ty.cast(Type.Payload.EnumFull).?.data; | 870 | break :blk 0; |
| 860 | if (enum_full.values.count() != 0) { | 871 | }, |
| 861 | return enum_full.values.keys()[field_index]; | 872 | // Assume it is already an integer and return it directly. |
| 862 | } else { | 873 | else => return val, |
| 863 | // Field index and integer values are the same. | 874 | }; |
| 864 | buffer.* = .{ | 875 | |
| 865 | .base = .{ .tag = .int_u64 }, | 876 | switch (ty.tag()) { |
| 866 | .data = field_index, | 877 | .enum_full, .enum_nonexhaustive => { |
| 867 | }; | 878 | const enum_full = ty.cast(Type.Payload.EnumFull).?.data; |
| 868 | return Value.initPayload(&buffer.base); | 879 | if (enum_full.values.count() != 0) { |
| 869 | } | 880 | return enum_full.values.keys()[field_index]; |
| 870 | }, | 881 | } else { |
| 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 => { | ||
| 885 | // Field index and integer values are the same. | 882 | // Field index and integer values are the same. |
| 886 | buffer.* = .{ | 883 | buffer.* = .{ |
| 887 | .base = .{ .tag = .int_u64 }, | 884 | .base = .{ .tag = .int_u64 }, |
| 888 | .data = field_index, | 885 | .data = field_index, |
| 889 | }; | 886 | }; |
| 890 | return Value.initPayload(&buffer.base); | 887 | return Value.initPayload(&buffer.base); |
| 891 | }, | 888 | } |
| 892 | else => unreachable, | 889 | }, |
| 893 | } | 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 | /// Asserts the value is an integer. | 915 | /// Asserts the value is an integer. |
| ... | @@ -901,6 +917,7 @@ pub const Value = extern union { | ... | @@ -901,6 +917,7 @@ pub const Value = extern union { |
| 901 | switch (self.tag()) { | 917 | switch (self.tag()) { |
| 902 | .zero, | 918 | .zero, |
| 903 | .bool_false, | 919 | .bool_false, |
| 920 | .the_only_possible_value, // i0, u0 | ||
| 904 | => return BigIntMutable.init(&space.limbs, 0).toConst(), | 921 | => return BigIntMutable.init(&space.limbs, 0).toConst(), |
| 905 | 922 | ||
| 906 | .one, | 923 | .one, |
| ... | @@ -922,6 +939,7 @@ pub const Value = extern union { | ... | @@ -922,6 +939,7 @@ pub const Value = extern union { |
| 922 | switch (self.tag()) { | 939 | switch (self.tag()) { |
| 923 | .zero, | 940 | .zero, |
| 924 | .bool_false, | 941 | .bool_false, |
| 942 | .the_only_possible_value, // i0, u0 | ||
| 925 | => return 0, | 943 | => return 0, |
| 926 | 944 | ||
| 927 | .one, | 945 | .one, |
| ... | @@ -943,6 +961,7 @@ pub const Value = extern union { | ... | @@ -943,6 +961,7 @@ pub const Value = extern union { |
| 943 | switch (self.tag()) { | 961 | switch (self.tag()) { |
| 944 | .zero, | 962 | .zero, |
| 945 | .bool_false, | 963 | .bool_false, |
| 964 | .the_only_possible_value, // i0, u0 | ||
| 946 | => return 0, | 965 | => return 0, |
| 947 | 966 | ||
| 948 | .one, | 967 | .one, |
| ... | @@ -1124,6 +1143,11 @@ pub const Value = extern union { | ... | @@ -1124,6 +1143,11 @@ pub const Value = extern union { |
| 1124 | @panic("TODO implement int_big_negative Value clz"); | 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 | else => unreachable, | 1151 | else => unreachable, |
| 1128 | } | 1152 | } |
| 1129 | } | 1153 | } |
| ... | @@ -1134,6 +1158,7 @@ pub const Value = extern union { | ... | @@ -1134,6 +1158,7 @@ pub const Value = extern union { |
| 1134 | switch (self.tag()) { | 1158 | switch (self.tag()) { |
| 1135 | .zero, | 1159 | .zero, |
| 1136 | .bool_false, | 1160 | .bool_false, |
| 1161 | .the_only_possible_value, | ||
| 1137 | => return 0, | 1162 | => return 0, |
| 1138 | 1163 | ||
| 1139 | .one, | 1164 | .one, |
| ... | @@ -1213,6 +1238,11 @@ pub const Value = extern union { | ... | @@ -1213,6 +1238,11 @@ pub const Value = extern union { |
| 1213 | else => unreachable, | 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 | else => unreachable, | 1246 | else => unreachable, |
| 1217 | } | 1247 | } |
| 1218 | } | 1248 | } |
| ... | @@ -1251,7 +1281,7 @@ pub const Value = extern union { | ... | @@ -1251,7 +1281,7 @@ pub const Value = extern union { |
| 1251 | /// Asserts the value is numeric | 1281 | /// Asserts the value is numeric |
| 1252 | pub fn isZero(self: Value) bool { | 1282 | pub fn isZero(self: Value) bool { |
| 1253 | return switch (self.tag()) { | 1283 | return switch (self.tag()) { |
| 1254 | .zero => true, | 1284 | .zero, .the_only_possible_value => true, |
| 1255 | .one => false, | 1285 | .one => false, |
| 1256 | 1286 | ||
| 1257 | .int_u64 => self.castTag(.int_u64).?.data == 0, | 1287 | .int_u64 => self.castTag(.int_u64).?.data == 0, |
| ... | @@ -1272,6 +1302,7 @@ pub const Value = extern union { | ... | @@ -1272,6 +1302,7 @@ pub const Value = extern union { |
| 1272 | return switch (lhs.tag()) { | 1302 | return switch (lhs.tag()) { |
| 1273 | .zero, | 1303 | .zero, |
| 1274 | .bool_false, | 1304 | .bool_false, |
| 1305 | .the_only_possible_value, | ||
| 1275 | => .eq, | 1306 | => .eq, |
| 1276 | 1307 | ||
| 1277 | .one, | 1308 | .one, |
| ... | @@ -1354,7 +1385,7 @@ pub const Value = extern union { | ... | @@ -1354,7 +1385,7 @@ pub const Value = extern union { |
| 1354 | assert(b_tag != .undef); | 1385 | assert(b_tag != .undef); |
| 1355 | if (a_tag == b_tag) { | 1386 | if (a_tag == b_tag) { |
| 1356 | switch (a_tag) { | 1387 | switch (a_tag) { |
| 1357 | .void_value, .null_value => return true, | 1388 | .void_value, .null_value, .the_only_possible_value => return true, |
| 1358 | .enum_literal => { | 1389 | .enum_literal => { |
| 1359 | const a_name = a.castTag(.enum_literal).?.data; | 1390 | const a_name = a.castTag(.enum_literal).?.data; |
| 1360 | const b_name = b.castTag(.enum_literal).?.data; | 1391 | const b_name = b.castTag(.enum_literal).?.data; |
| ... | @@ -1706,6 +1737,9 @@ pub const Value = extern union { | ... | @@ -1706,6 +1737,9 @@ pub const Value = extern union { |
| 1706 | .decl_ref => return val.castTag(.decl_ref).?.data.val.elemValueAdvanced(index, arena, buffer), | 1737 | .decl_ref => return val.castTag(.decl_ref).?.data.val.elemValueAdvanced(index, arena, buffer), |
| 1707 | .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.val.elemValueAdvanced(index, arena, buffer), | 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 | else => unreachable, | 1743 | else => unreachable, |
| 1710 | } | 1744 | } |
| 1711 | } | 1745 | } |
| ... | @@ -1722,6 +1756,8 @@ pub const Value = extern union { | ... | @@ -1722,6 +1756,8 @@ pub const Value = extern union { |
| 1722 | // TODO assert the tag is correct | 1756 | // TODO assert the tag is correct |
| 1723 | return payload.val; | 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 | else => unreachable, | 1762 | else => unreachable, |
| 1727 | } | 1763 | } |
| ... | @@ -1820,6 +1856,7 @@ pub const Value = extern union { | ... | @@ -1820,6 +1856,7 @@ pub const Value = extern union { |
| 1820 | pub fn intToFloat(val: Value, allocator: *Allocator, dest_ty: Type, target: Target) !Value { | 1856 | pub fn intToFloat(val: Value, allocator: *Allocator, dest_ty: Type, target: Target) !Value { |
| 1821 | switch (val.tag()) { | 1857 | switch (val.tag()) { |
| 1822 | .undef, .zero, .one => return val, | 1858 | .undef, .zero, .one => return val, |
| 1859 | .the_only_possible_value => return Value.initTag(.zero), // for i0, u0 | ||
| 1823 | .int_u64 => { | 1860 | .int_u64 => { |
| 1824 | return intToFloatInner(val.castTag(.int_u64).?.data, allocator, dest_ty, target); | 1861 | return intToFloatInner(val.castTag(.int_u64).?.data, allocator, dest_ty, target); |
| 1825 | }, | 1862 | }, |