| author | |
| committer | |
| log | 30a824cb9e148adb0799a0a81721160c0d474b50 |
| tree | afdfb0a3e19fb956c66ade7b190b7ca4566ba7f7 |
| parent | 7e56028bc7c00b884c92e2948728cbc47e5a8a09 |
The following AST avoids unnecessary derefs now:
* error set decl
* field access
* array access
* for loops: replace ensure_indexable and deref on the len_ptr with a
special purpose ZIR instruction called indexable_ptr_len.
Added an error note when for loop operand is the wrong type.
I also accidentally implemented `@field`.8 files changed, 394 insertions(+), 222 deletions(-)
src/Module.zig+163| ... | ... | @@ -2357,6 +2357,11 @@ pub fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*De |
| 2357 | 2357 | return self.decl_table.get(name_hash); |
| 2358 | 2358 | } |
| 2359 | 2359 | |
| 2360 | pub fn analyzeDeclVal(mod: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst { | |
| 2361 | const decl_ref = try mod.analyzeDeclRef(scope, src, decl); | |
| 2362 | return mod.analyzeDeref(scope, src, decl_ref, src); | |
| 2363 | } | |
| 2364 | ||
| 2360 | 2365 | pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst { |
| 2361 | 2366 | const scope_decl = scope.ownerDecl().?; |
| 2362 | 2367 | try self.declareDeclDependency(scope_decl, decl); |
| ... | ... | @@ -2408,6 +2413,20 @@ fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) Inner |
| 2408 | 2413 | return &inst.base; |
| 2409 | 2414 | } |
| 2410 | 2415 | |
| 2416 | pub fn analyzeRef(mod: *Module, scope: *Scope, src: usize, operand: *Inst) InnerError!*Inst { | |
| 2417 | const ptr_type = try mod.simplePtrType(scope, src, operand.ty, false, .One); | |
| 2418 | ||
| 2419 | if (operand.value()) |val| { | |
| 2420 | return mod.constInst(scope, src, .{ | |
| 2421 | .ty = ptr_type, | |
| 2422 | .val = try Value.Tag.ref_val.create(scope.arena(), val), | |
| 2423 | }); | |
| 2424 | } | |
| 2425 | ||
| 2426 | const b = try mod.requireRuntimeBlock(scope, src); | |
| 2427 | return mod.addUnOp(b, src, ptr_type, .ref, operand); | |
| 2428 | } | |
| 2429 | ||
| 2411 | 2430 | pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst { |
| 2412 | 2431 | const elem_ty = switch (ptr.ty.zigTypeTag()) { |
| 2413 | 2432 | .Pointer => ptr.ty.elemType(), |
| ... | ... | @@ -3543,3 +3562,147 @@ pub fn emitBackwardBranch(mod: *Module, block: *Scope.Block, src: usize) !void { |
| 3543 | 3562 | }); |
| 3544 | 3563 | } |
| 3545 | 3564 | } |
| 3565 | ||
| 3566 | pub fn namedFieldPtr( | |
| 3567 | mod: *Module, | |
| 3568 | scope: *Scope, | |
| 3569 | src: usize, | |
| 3570 | object_ptr: *Inst, | |
| 3571 | field_name: []const u8, | |
| 3572 | field_name_src: usize, | |
| 3573 | ) InnerError!*Inst { | |
| 3574 | const elem_ty = switch (object_ptr.ty.zigTypeTag()) { | |
| 3575 | .Pointer => object_ptr.ty.elemType(), | |
| 3576 | else => return mod.fail(scope, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}), | |
| 3577 | }; | |
| 3578 | switch (elem_ty.zigTypeTag()) { | |
| 3579 | .Array => { | |
| 3580 | if (mem.eql(u8, field_name, "len")) { | |
| 3581 | return mod.constInst(scope, src, .{ | |
| 3582 | .ty = Type.initTag(.single_const_pointer_to_comptime_int), | |
| 3583 | .val = try Value.Tag.ref_val.create( | |
| 3584 | scope.arena(), | |
| 3585 | try Value.Tag.int_u64.create(scope.arena(), elem_ty.arrayLen()), | |
| 3586 | ), | |
| 3587 | }); | |
| 3588 | } else { | |
| 3589 | return mod.fail( | |
| 3590 | scope, | |
| 3591 | field_name_src, | |
| 3592 | "no member named '{s}' in '{}'", | |
| 3593 | .{ field_name, elem_ty }, | |
| 3594 | ); | |
| 3595 | } | |
| 3596 | }, | |
| 3597 | .Pointer => { | |
| 3598 | const ptr_child = elem_ty.elemType(); | |
| 3599 | switch (ptr_child.zigTypeTag()) { | |
| 3600 | .Array => { | |
| 3601 | if (mem.eql(u8, field_name, "len")) { | |
| 3602 | return mod.constInst(scope, src, .{ | |
| 3603 | .ty = Type.initTag(.single_const_pointer_to_comptime_int), | |
| 3604 | .val = try Value.Tag.ref_val.create( | |
| 3605 | scope.arena(), | |
| 3606 | try Value.Tag.int_u64.create(scope.arena(), ptr_child.arrayLen()), | |
| 3607 | ), | |
| 3608 | }); | |
| 3609 | } else { | |
| 3610 | return mod.fail( | |
| 3611 | scope, | |
| 3612 | field_name_src, | |
| 3613 | "no member named '{s}' in '{}'", | |
| 3614 | .{ field_name, elem_ty }, | |
| 3615 | ); | |
| 3616 | } | |
| 3617 | }, | |
| 3618 | else => {}, | |
| 3619 | } | |
| 3620 | }, | |
| 3621 | .Type => { | |
| 3622 | _ = try mod.resolveConstValue(scope, object_ptr); | |
| 3623 | const result = try mod.analyzeDeref(scope, src, object_ptr, object_ptr.src); | |
| 3624 | const val = result.value().?; | |
| 3625 | const child_type = try val.toType(scope.arena()); | |
| 3626 | switch (child_type.zigTypeTag()) { | |
| 3627 | .ErrorSet => { | |
| 3628 | // TODO resolve inferred error sets | |
| 3629 | const entry = if (val.castTag(.error_set)) |payload| | |
| 3630 | (payload.data.fields.getEntry(field_name) orelse | |
| 3631 | return mod.fail(scope, src, "no error named '{s}' in '{}'", .{ field_name, child_type })).* | |
| 3632 | else | |
| 3633 | try mod.getErrorValue(field_name); | |
| 3634 | ||
| 3635 | const result_type = if (child_type.tag() == .anyerror) | |
| 3636 | try Type.Tag.error_set_single.create(scope.arena(), entry.key) | |
| 3637 | else | |
| 3638 | child_type; | |
| 3639 | ||
| 3640 | return mod.constInst(scope, src, .{ | |
| 3641 | .ty = try mod.simplePtrType(scope, src, result_type, false, .One), | |
| 3642 | .val = try Value.Tag.ref_val.create( | |
| 3643 | scope.arena(), | |
| 3644 | try Value.Tag.@"error".create(scope.arena(), .{ | |
| 3645 | .name = entry.key, | |
| 3646 | .value = entry.value, | |
| 3647 | }), | |
| 3648 | ), | |
| 3649 | }); | |
| 3650 | }, | |
| 3651 | .Struct => { | |
| 3652 | const container_scope = child_type.getContainerScope(); | |
| 3653 | if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| { | |
| 3654 | // TODO if !decl.is_pub and inDifferentFiles() "{} is private" | |
| 3655 | return mod.analyzeDeclRef(scope, src, decl); | |
| 3656 | } | |
| 3657 | ||
| 3658 | if (container_scope.file_scope == mod.root_scope) { | |
| 3659 | return mod.fail(scope, src, "root source file has no member called '{s}'", .{field_name}); | |
| 3660 | } else { | |
| 3661 | return mod.fail(scope, src, "container '{}' has no member called '{s}'", .{ child_type, field_name }); | |
| 3662 | } | |
| 3663 | }, | |
| 3664 | else => return mod.fail(scope, src, "type '{}' does not support field access", .{child_type}), | |
| 3665 | } | |
| 3666 | }, | |
| 3667 | else => {}, | |
| 3668 | } | |
| 3669 | return mod.fail(scope, src, "type '{}' does not support field access", .{elem_ty}); | |
| 3670 | } | |
| 3671 | ||
| 3672 | pub fn elemPtr( | |
| 3673 | mod: *Module, | |
| 3674 | scope: *Scope, | |
| 3675 | src: usize, | |
| 3676 | array_ptr: *Inst, | |
| 3677 | elem_index: *Inst, | |
| 3678 | ) InnerError!*Inst { | |
| 3679 | const elem_ty = switch (array_ptr.ty.zigTypeTag()) { | |
| 3680 | .Pointer => array_ptr.ty.elemType(), | |
| 3681 | else => return mod.fail(scope, array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}), | |
| 3682 | }; | |
| 3683 | if (!elem_ty.isIndexable()) { | |
| 3684 | return mod.fail(scope, src, "array access of non-array type '{}'", .{elem_ty}); | |
| 3685 | } | |
| 3686 | ||
| 3687 | if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) { | |
| 3688 | // we have to deref the ptr operand to get the actual array pointer | |
| 3689 | const array_ptr_deref = try mod.analyzeDeref(scope, src, array_ptr, array_ptr.src); | |
| 3690 | if (array_ptr_deref.value()) |array_ptr_val| { | |
| 3691 | if (elem_index.value()) |index_val| { | |
| 3692 | // Both array pointer and index are compile-time known. | |
| 3693 | const index_u64 = index_val.toUnsignedInt(); | |
| 3694 | // @intCast here because it would have been impossible to construct a value that | |
| 3695 | // required a larger index. | |
| 3696 | const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64)); | |
| 3697 | const pointee_type = elem_ty.elemType().elemType(); | |
| 3698 | ||
| 3699 | return mod.constInst(scope, src, .{ | |
| 3700 | .ty = try Type.Tag.single_const_pointer.create(scope.arena(), pointee_type), | |
| 3701 | .val = elem_ptr, | |
| 3702 | }); | |
| 3703 | } | |
| 3704 | } | |
| 3705 | } | |
| 3706 | ||
| 3707 | return mod.fail(scope, src, "TODO implement more analyze elemptr", .{}); | |
| 3708 | } |
src/astgen.zig+85-30| ... | ... | @@ -278,7 +278,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 278 | 278 | .ErrorUnion => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.ErrorUnion).?, .error_union_type)), |
| 279 | 279 | .MergeErrorSets => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.MergeErrorSets).?, .merge_error_sets)), |
| 280 | 280 | .AnyFrameType => return rlWrap(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)), |
| 281 | .ErrorSetDecl => return errorSetDecl(mod, scope, rl, node.castTag(.ErrorSetDecl).?), | |
| 281 | .ErrorSetDecl => return rlWrap(mod, scope, rl, try errorSetDecl(mod, scope, node.castTag(.ErrorSetDecl).?)), | |
| 282 | 282 | .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), |
| 283 | 283 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), |
| 284 | 284 | .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?), |
| ... | ... | @@ -1107,7 +1107,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con |
| 1107 | 1107 | } |
| 1108 | 1108 | } |
| 1109 | 1109 | |
| 1110 | fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst { | |
| 1110 | fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst { | |
| 1111 | 1111 | const tree = scope.tree(); |
| 1112 | 1112 | const src = tree.token_locs[node.error_token].start; |
| 1113 | 1113 | const decls = node.decls(); |
| ... | ... | @@ -1118,9 +1118,7 @@ fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Erro |
| 1118 | 1118 | fields[i] = try mod.identifierTokenString(scope, tag.name_token); |
| 1119 | 1119 | } |
| 1120 | 1120 | |
| 1121 | // analyzing the error set results in a decl ref, so we might need to dereference it | |
| 1122 | // TODO remove all callsites to rlWrapPtr | |
| 1123 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{})); | |
| 1121 | return addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{}); | |
| 1124 | 1122 | } |
| 1125 | 1123 | |
| 1126 | 1124 | fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst { |
| ... | ... | @@ -1299,35 +1297,72 @@ fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: as |
| 1299 | 1297 | return mem.eql(u8, ident_name_1, ident_name_2); |
| 1300 | 1298 | } |
| 1301 | 1299 | |
| 1302 | pub fn identifierStringInst(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst { | |
| 1300 | pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst { | |
| 1303 | 1301 | const tree = scope.tree(); |
| 1304 | const src = tree.token_locs[node.token].start; | |
| 1305 | ||
| 1306 | const ident_name = try mod.identifierTokenString(scope, node.token); | |
| 1307 | ||
| 1308 | return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = ident_name }, .{}); | |
| 1302 | const src = tree.token_locs[node.op_token].start; | |
| 1303 | // TODO custom AST node for field access so that we don't have to go through a node cast here | |
| 1304 | const field_name = try mod.identifierTokenString(scope, node.rhs.castTag(.Identifier).?.token); | |
| 1305 | if (rl == .ref) { | |
| 1306 | return addZirInstTag(mod, scope, src, .field_ptr, .{ | |
| 1307 | .object = try expr(mod, scope, .ref, node.lhs), | |
| 1308 | .field_name = field_name, | |
| 1309 | }); | |
| 1310 | } | |
| 1311 | return rlWrap(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val, .{ | |
| 1312 | .object = try expr(mod, scope, .none, node.lhs), | |
| 1313 | .field_name = field_name, | |
| 1314 | })); | |
| 1309 | 1315 | } |
| 1310 | 1316 | |
| 1311 | fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst { | |
| 1317 | fn namedField( | |
| 1318 | mod: *Module, | |
| 1319 | scope: *Scope, | |
| 1320 | rl: ResultLoc, | |
| 1321 | call: *ast.Node.BuiltinCall, | |
| 1322 | ) InnerError!*zir.Inst { | |
| 1323 | try ensureBuiltinParamCount(mod, scope, call, 2); | |
| 1324 | ||
| 1312 | 1325 | const tree = scope.tree(); |
| 1313 | const src = tree.token_locs[node.op_token].start; | |
| 1326 | const src = tree.token_locs[call.builtin_token].start; | |
| 1327 | const params = call.params(); | |
| 1314 | 1328 | |
| 1315 | const lhs = try expr(mod, scope, .ref, node.lhs); | |
| 1316 | const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?); | |
| 1329 | const string_type = try addZIRInstConst(mod, scope, src, .{ | |
| 1330 | .ty = Type.initTag(.type), | |
| 1331 | .val = Value.initTag(.const_slice_u8_type), | |
| 1332 | }); | |
| 1333 | const string_rl: ResultLoc = .{ .ty = string_type }; | |
| 1317 | 1334 | |
| 1318 | // TODO remove all callsites to rlWrapPtr | |
| 1319 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{})); | |
| 1335 | if (rl == .ref) { | |
| 1336 | return addZirInstTag(mod, scope, src, .field_ptr_named, .{ | |
| 1337 | .object = try expr(mod, scope, .ref, params[0]), | |
| 1338 | .field_name = try comptimeExpr(mod, scope, string_rl, params[1]), | |
| 1339 | }); | |
| 1340 | } | |
| 1341 | return rlWrap(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val_named, .{ | |
| 1342 | .object = try expr(mod, scope, .none, params[0]), | |
| 1343 | .field_name = try comptimeExpr(mod, scope, string_rl, params[1]), | |
| 1344 | })); | |
| 1320 | 1345 | } |
| 1321 | 1346 | |
| 1322 | 1347 | fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ArrayAccess) InnerError!*zir.Inst { |
| 1323 | 1348 | const tree = scope.tree(); |
| 1324 | 1349 | const src = tree.token_locs[node.rtoken].start; |
| 1350 | const usize_type = try addZIRInstConst(mod, scope, src, .{ | |
| 1351 | .ty = Type.initTag(.type), | |
| 1352 | .val = Value.initTag(.usize_type), | |
| 1353 | }); | |
| 1354 | const index_rl: ResultLoc = .{ .ty = usize_type }; | |
| 1325 | 1355 | |
| 1326 | const array_ptr = try expr(mod, scope, .ref, node.lhs); | |
| 1327 | const index = try expr(mod, scope, .none, node.index_expr); | |
| 1328 | ||
| 1329 | // TODO remove all callsites to rlWrapPtr | |
| 1330 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ElemPtr, .{ .array_ptr = array_ptr, .index = index }, .{})); | |
| 1356 | if (rl == .ref) { | |
| 1357 | return addZirInstTag(mod, scope, src, .elem_ptr, .{ | |
| 1358 | .array = try expr(mod, scope, .ref, node.lhs), | |
| 1359 | .index = try expr(mod, scope, index_rl, node.index_expr), | |
| 1360 | }); | |
| 1361 | } | |
| 1362 | return rlWrap(mod, scope, rl, try addZirInstTag(mod, scope, src, .elem_val, .{ | |
| 1363 | .array = try expr(mod, scope, .none, node.lhs), | |
| 1364 | .index = try expr(mod, scope, index_rl, node.index_expr), | |
| 1365 | })); | |
| 1331 | 1366 | } |
| 1332 | 1367 | |
| 1333 | 1368 | fn sliceExpr(mod: *Module, scope: *Scope, node: *ast.Node.Slice) InnerError!*zir.Inst { |
| ... | ... | @@ -1819,12 +1854,8 @@ fn forExpr( |
| 1819 | 1854 | break :blk index_ptr; |
| 1820 | 1855 | }; |
| 1821 | 1856 | const array_ptr = try expr(mod, &for_scope.base, .ref, for_node.array_expr); |
| 1822 | _ = try addZIRUnOp(mod, &for_scope.base, for_node.array_expr.firstToken(), .ensure_indexable, array_ptr); | |
| 1823 | 1857 | const cond_src = tree.token_locs[for_node.array_expr.firstToken()].start; |
| 1824 | const len_ptr = try addZIRInst(mod, &for_scope.base, cond_src, zir.Inst.FieldPtr, .{ | |
| 1825 | .object_ptr = array_ptr, | |
| 1826 | .field_name = try addZIRInst(mod, &for_scope.base, cond_src, zir.Inst.Str, .{ .bytes = "len" }, .{}), | |
| 1827 | }, .{}); | |
| 1858 | const len = try addZIRUnOp(mod, &for_scope.base, cond_src, .indexable_ptr_len, array_ptr); | |
| 1828 | 1859 | |
| 1829 | 1860 | var loop_scope: Scope.GenZIR = .{ |
| 1830 | 1861 | .parent = &for_scope.base, |
| ... | ... | @@ -1845,7 +1876,6 @@ fn forExpr( |
| 1845 | 1876 | |
| 1846 | 1877 | // check condition i < array_expr.len |
| 1847 | 1878 | const index = try addZIRUnOp(mod, &cond_scope.base, cond_src, .deref, index_ptr); |
| 1848 | const len = try addZIRUnOp(mod, &cond_scope.base, cond_src, .deref, len_ptr); | |
| 1849 | 1879 | const cond = try addZIRBinOp(mod, &cond_scope.base, cond_src, .cmp_lt, index, len); |
| 1850 | 1880 | |
| 1851 | 1881 | const condbr = try addZIRInstSpecial(mod, &cond_scope.base, for_src, zir.Inst.CondBr, .{ |
| ... | ... | @@ -2328,8 +2358,9 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo |
| 2328 | 2358 | .local_ptr => { |
| 2329 | 2359 | const local_ptr = s.cast(Scope.LocalPtr).?; |
| 2330 | 2360 | if (mem.eql(u8, local_ptr.name, ident_name)) { |
| 2331 | // TODO remove all callsites to rlWrapPtr | |
| 2332 | return rlWrapPtr(mod, scope, rl, local_ptr.ptr); | |
| 2361 | if (rl == .ref) return local_ptr.ptr; | |
| 2362 | const loaded = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr); | |
| 2363 | return rlWrap(mod, scope, rl, loaded); | |
| 2333 | 2364 | } |
| 2334 | 2365 | s = local_ptr.parent; |
| 2335 | 2366 | }, |
| ... | ... | @@ -2747,6 +2778,8 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built |
| 2747 | 2778 | return setEvalBranchQuota(mod, scope, call); |
| 2748 | 2779 | } else if (mem.eql(u8, builtin_name, "@compileLog")) { |
| 2749 | 2780 | return compileLog(mod, scope, call); |
| 2781 | } else if (mem.eql(u8, builtin_name, "@field")) { | |
| 2782 | return namedField(mod, scope, rl, call); | |
| 2750 | 2783 | } else { |
| 2751 | 2784 | return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{s}'", .{builtin_name}); |
| 2752 | 2785 | } |
| ... | ... | @@ -3119,6 +3152,28 @@ fn rlWrapPtr(mod: *Module, scope: *Scope, rl: ResultLoc, ptr: *zir.Inst) InnerEr |
| 3119 | 3152 | return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, ptr.src, .deref, ptr)); |
| 3120 | 3153 | } |
| 3121 | 3154 | |
| 3155 | pub fn addZirInstTag( | |
| 3156 | mod: *Module, | |
| 3157 | scope: *Scope, | |
| 3158 | src: usize, | |
| 3159 | comptime tag: zir.Inst.Tag, | |
| 3160 | positionals: std.meta.fieldInfo(tag.Type(), .positionals).field_type, | |
| 3161 | ) !*zir.Inst { | |
| 3162 | const gen_zir = scope.getGenZIR(); | |
| 3163 | try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1); | |
| 3164 | const inst = try gen_zir.arena.create(tag.Type()); | |
| 3165 | inst.* = .{ | |
| 3166 | .base = .{ | |
| 3167 | .tag = tag, | |
| 3168 | .src = src, | |
| 3169 | }, | |
| 3170 | .positionals = positionals, | |
| 3171 | .kw_args = .{}, | |
| 3172 | }; | |
| 3173 | gen_zir.instructions.appendAssumeCapacity(&inst.base); | |
| 3174 | return &inst.base; | |
| 3175 | } | |
| 3176 | ||
| 3122 | 3177 | pub fn addZIRInstSpecial( |
| 3123 | 3178 | mod: *Module, |
| 3124 | 3179 | scope: *Scope, |
src/zir.zig+43-17| ... | ... | @@ -47,6 +47,10 @@ pub const Inst = struct { |
| 47 | 47 | array_type, |
| 48 | 48 | /// Create an array type with sentinel |
| 49 | 49 | array_type_sentinel, |
| 50 | /// Given a pointer to an indexable object, returns the len property. This is | |
| 51 | /// used by for loops. This instruction also emits a for-loop specific instruction | |
| 52 | /// if the indexable object is not indexable. | |
| 53 | indexable_ptr_len, | |
| 50 | 54 | /// Function parameter value. These must be first in a function's main block, |
| 51 | 55 | /// in respective order with the parameters. |
| 52 | 56 | arg, |
| ... | ... | @@ -142,13 +146,13 @@ pub const Inst = struct { |
| 142 | 146 | div, |
| 143 | 147 | /// Given a pointer to an array, slice, or pointer, returns a pointer to the element at |
| 144 | 148 | /// the provided index. |
| 145 | elemptr, | |
| 149 | elem_ptr, | |
| 150 | /// Given an array, slice, or pointer, returns the element at the provided index. | |
| 151 | elem_val, | |
| 146 | 152 | /// Emits a compile error if the operand is not `void`. |
| 147 | 153 | ensure_result_used, |
| 148 | 154 | /// Emits a compile error if an error is ignored. |
| 149 | 155 | ensure_result_non_error, |
| 150 | /// Emits a compile error if operand cannot be indexed. | |
| 151 | ensure_indexable, | |
| 152 | 156 | /// Create a `E!T` type. |
| 153 | 157 | error_union_type, |
| 154 | 158 | /// Create an error set. |
| ... | ... | @@ -156,8 +160,17 @@ pub const Inst = struct { |
| 156 | 160 | /// Export the provided Decl as the provided name in the compilation's output object file. |
| 157 | 161 | @"export", |
| 158 | 162 | /// Given a pointer to a struct or object that contains virtual fields, returns a pointer |
| 159 | /// to the named field. | |
| 160 | fieldptr, | |
| 163 | /// to the named field. The field name is a []const u8. Used by a.b syntax. | |
| 164 | field_ptr, | |
| 165 | /// Given a struct or object that contains virtual fields, returns the named field. | |
| 166 | /// The field name is a []const u8. Used by a.b syntax. | |
| 167 | field_val, | |
| 168 | /// Given a pointer to a struct or object that contains virtual fields, returns a pointer | |
| 169 | /// to the named field. The field name is a comptime instruction. Used by @field. | |
| 170 | field_ptr_named, | |
| 171 | /// Given a struct or object that contains virtual fields, returns the named field. | |
| 172 | /// The field name is a comptime instruction. Used by @field. | |
| 173 | field_val_named, | |
| 161 | 174 | /// Convert a larger float type to any other float type, possibly causing a loss of precision. |
| 162 | 175 | floatcast, |
| 163 | 176 | /// Declare a function body. |
| ... | ... | @@ -361,7 +374,6 @@ pub const Inst = struct { |
| 361 | 374 | .ptrtoint, |
| 362 | 375 | .ensure_result_used, |
| 363 | 376 | .ensure_result_non_error, |
| 364 | .ensure_indexable, | |
| 365 | 377 | .bitcast_result_ptr, |
| 366 | 378 | .ref, |
| 367 | 379 | .bitcast_ref, |
| ... | ... | @@ -391,6 +403,7 @@ pub const Inst = struct { |
| 391 | 403 | .bitnot, |
| 392 | 404 | .import, |
| 393 | 405 | .set_eval_branch_quota, |
| 406 | .indexable_ptr_len, | |
| 394 | 407 | => UnOp, |
| 395 | 408 | |
| 396 | 409 | .add, |
| ... | ... | @@ -452,14 +465,15 @@ pub const Inst = struct { |
| 452 | 465 | .str => Str, |
| 453 | 466 | .int => Int, |
| 454 | 467 | .inttype => IntType, |
| 455 | .fieldptr => FieldPtr, | |
| 468 | .field_ptr, .field_val => Field, | |
| 469 | .field_ptr_named, .field_val_named => FieldNamed, | |
| 456 | 470 | .@"asm" => Asm, |
| 457 | 471 | .@"fn" => Fn, |
| 458 | 472 | .@"export" => Export, |
| 459 | 473 | .param_type => ParamType, |
| 460 | 474 | .primitive => Primitive, |
| 461 | 475 | .fntype => FnType, |
| 462 | .elemptr => ElemPtr, | |
| 476 | .elem_ptr, .elem_val => Elem, | |
| 463 | 477 | .condbr => CondBr, |
| 464 | 478 | .ptr_type => PtrType, |
| 465 | 479 | .enum_literal => EnumLiteral, |
| ... | ... | @@ -490,6 +504,7 @@ pub const Inst = struct { |
| 490 | 504 | .array_mul, |
| 491 | 505 | .array_type, |
| 492 | 506 | .array_type_sentinel, |
| 507 | .indexable_ptr_len, | |
| 493 | 508 | .arg, |
| 494 | 509 | .as, |
| 495 | 510 | .@"asm", |
| ... | ... | @@ -523,13 +538,16 @@ pub const Inst = struct { |
| 523 | 538 | .declval, |
| 524 | 539 | .deref, |
| 525 | 540 | .div, |
| 526 | .elemptr, | |
| 541 | .elem_ptr, | |
| 542 | .elem_val, | |
| 527 | 543 | .ensure_result_used, |
| 528 | 544 | .ensure_result_non_error, |
| 529 | .ensure_indexable, | |
| 530 | 545 | .@"export", |
| 531 | 546 | .floatcast, |
| 532 | .fieldptr, | |
| 547 | .field_ptr, | |
| 548 | .field_val, | |
| 549 | .field_ptr_named, | |
| 550 | .field_val_named, | |
| 533 | 551 | .@"fn", |
| 534 | 552 | .fntype, |
| 535 | 553 | .int, |
| ... | ... | @@ -823,12 +841,21 @@ pub const Inst = struct { |
| 823 | 841 | kw_args: struct {}, |
| 824 | 842 | }; |
| 825 | 843 | |
| 826 | pub const FieldPtr = struct { | |
| 827 | pub const base_tag = Tag.fieldptr; | |
| 844 | pub const Field = struct { | |
| 828 | 845 | base: Inst, |
| 829 | 846 | |
| 830 | 847 | positionals: struct { |
| 831 | object_ptr: *Inst, | |
| 848 | object: *Inst, | |
| 849 | field_name: []const u8, | |
| 850 | }, | |
| 851 | kw_args: struct {}, | |
| 852 | }; | |
| 853 | ||
| 854 | pub const FieldNamed = struct { | |
| 855 | base: Inst, | |
| 856 | ||
| 857 | positionals: struct { | |
| 858 | object: *Inst, | |
| 832 | 859 | field_name: *Inst, |
| 833 | 860 | }, |
| 834 | 861 | kw_args: struct {}, |
| ... | ... | @@ -1000,12 +1027,11 @@ pub const Inst = struct { |
| 1000 | 1027 | }; |
| 1001 | 1028 | }; |
| 1002 | 1029 | |
| 1003 | pub const ElemPtr = struct { | |
| 1004 | pub const base_tag = Tag.elemptr; | |
| 1030 | pub const Elem = struct { | |
| 1005 | 1031 | base: Inst, |
| 1006 | 1032 | |
| 1007 | 1033 | positionals: struct { |
| 1008 | array_ptr: *Inst, | |
| 1034 | array: *Inst, | |
| 1009 | 1035 | index: *Inst, |
| 1010 | 1036 | }, |
| 1011 | 1037 | kw_args: struct {}, |
src/zir_sema.zig+99-171| ... | ... | @@ -43,8 +43,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 43 | 43 | .inferred_alloc_mut, |
| 44 | 44 | ), |
| 45 | 45 | .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?), |
| 46 | .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?), | |
| 47 | .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?), | |
| 46 | .bitcast_ref => return bitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?), | |
| 47 | .bitcast_result_ptr => return bitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?), | |
| 48 | 48 | .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?, false), |
| 49 | 49 | .block_comptime => return analyzeInstBlock(mod, scope, old_inst.castTag(.block_comptime).?, true), |
| 50 | 50 | .block_flat => return analyzeInstBlockFlat(mod, scope, old_inst.castTag(.block_flat).?, false), |
| ... | ... | @@ -52,7 +52,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 52 | 52 | .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?), |
| 53 | 53 | .breakpoint => return analyzeInstBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?), |
| 54 | 54 | .breakvoid => return analyzeInstBreakVoid(mod, scope, old_inst.castTag(.breakvoid).?), |
| 55 | .call => return analyzeInstCall(mod, scope, old_inst.castTag(.call).?), | |
| 55 | .call => return call(mod, scope, old_inst.castTag(.call).?), | |
| 56 | 56 | .coerce_result_block_ptr => return analyzeInstCoerceResultBlockPtr(mod, scope, old_inst.castTag(.coerce_result_block_ptr).?), |
| 57 | 57 | .coerce_result_ptr => return analyzeInstCoerceResultPtr(mod, scope, old_inst.castTag(.coerce_result_ptr).?), |
| 58 | 58 | .coerce_to_ptr_elem => return analyzeInstCoerceToPtrElem(mod, scope, old_inst.castTag(.coerce_to_ptr_elem).?), |
| ... | ... | @@ -60,13 +60,13 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 60 | 60 | .compilelog => return analyzeInstCompileLog(mod, scope, old_inst.castTag(.compilelog).?), |
| 61 | 61 | .@"const" => return analyzeInstConst(mod, scope, old_inst.castTag(.@"const").?), |
| 62 | 62 | .dbg_stmt => return analyzeInstDbgStmt(mod, scope, old_inst.castTag(.dbg_stmt).?), |
| 63 | .declref => return analyzeInstDeclRef(mod, scope, old_inst.castTag(.declref).?), | |
| 63 | .declref => return declRef(mod, scope, old_inst.castTag(.declref).?), | |
| 64 | 64 | .declref_str => return analyzeInstDeclRefStr(mod, scope, old_inst.castTag(.declref_str).?), |
| 65 | .declval => return analyzeInstDeclVal(mod, scope, old_inst.castTag(.declval).?), | |
| 65 | .declval => return declVal(mod, scope, old_inst.castTag(.declval).?), | |
| 66 | 66 | .ensure_result_used => return analyzeInstEnsureResultUsed(mod, scope, old_inst.castTag(.ensure_result_used).?), |
| 67 | 67 | .ensure_result_non_error => return analyzeInstEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?), |
| 68 | .ensure_indexable => return analyzeInstEnsureIndexable(mod, scope, old_inst.castTag(.ensure_indexable).?), | |
| 69 | .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?), | |
| 68 | .indexable_ptr_len => return indexablePtrLen(mod, scope, old_inst.castTag(.indexable_ptr_len).?), | |
| 69 | .ref => return ref(mod, scope, old_inst.castTag(.ref).?), | |
| 70 | 70 | .resolve_inferred_alloc => return analyzeInstResolveInferredAlloc(mod, scope, old_inst.castTag(.resolve_inferred_alloc).?), |
| 71 | 71 | .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?), |
| 72 | 72 | .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?), |
| ... | ... | @@ -88,7 +88,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 88 | 88 | .loop => return analyzeInstLoop(mod, scope, old_inst.castTag(.loop).?), |
| 89 | 89 | .param_type => return analyzeInstParamType(mod, scope, old_inst.castTag(.param_type).?), |
| 90 | 90 | .ptrtoint => return analyzeInstPtrToInt(mod, scope, old_inst.castTag(.ptrtoint).?), |
| 91 | .fieldptr => return analyzeInstFieldPtr(mod, scope, old_inst.castTag(.fieldptr).?), | |
| 91 | .field_ptr => return fieldPtr(mod, scope, old_inst.castTag(.field_ptr).?), | |
| 92 | .field_val => return fieldVal(mod, scope, old_inst.castTag(.field_val).?), | |
| 93 | .field_ptr_named => return fieldPtrNamed(mod, scope, old_inst.castTag(.field_ptr_named).?), | |
| 94 | .field_val_named => return fieldValNamed(mod, scope, old_inst.castTag(.field_val_named).?), | |
| 92 | 95 | .deref => return analyzeInstDeref(mod, scope, old_inst.castTag(.deref).?), |
| 93 | 96 | .as => return analyzeInstAs(mod, scope, old_inst.castTag(.as).?), |
| 94 | 97 | .@"asm" => return analyzeInstAsm(mod, scope, old_inst.castTag(.@"asm").?), |
| ... | ... | @@ -103,7 +106,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 103 | 106 | .intcast => return analyzeInstIntCast(mod, scope, old_inst.castTag(.intcast).?), |
| 104 | 107 | .bitcast => return analyzeInstBitCast(mod, scope, old_inst.castTag(.bitcast).?), |
| 105 | 108 | .floatcast => return analyzeInstFloatCast(mod, scope, old_inst.castTag(.floatcast).?), |
| 106 | .elemptr => return analyzeInstElemPtr(mod, scope, old_inst.castTag(.elemptr).?), | |
| 109 | .elem_ptr => return elemPtr(mod, scope, old_inst.castTag(.elem_ptr).?), | |
| 110 | .elem_val => return elemVal(mod, scope, old_inst.castTag(.elem_val).?), | |
| 107 | 111 | .add => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.add).?), |
| 108 | 112 | .addwrap => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.addwrap).?), |
| 109 | 113 | .sub => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.sub).?), |
| ... | ... | @@ -281,16 +285,16 @@ fn analyzeInstCoerceResultBlockPtr( |
| 281 | 285 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{}); |
| 282 | 286 | } |
| 283 | 287 | |
| 284 | fn analyzeInstBitCastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 288 | fn bitCastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 285 | 289 | const tracy = trace(@src()); |
| 286 | 290 | defer tracy.end(); |
| 287 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastRef", .{}); | |
| 291 | return mod.fail(scope, inst.base.src, "TODO implement zir_sema.bitCastRef", .{}); | |
| 288 | 292 | } |
| 289 | 293 | |
| 290 | fn analyzeInstBitCastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 294 | fn bitCastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 291 | 295 | const tracy = trace(@src()); |
| 292 | 296 | defer tracy.end(); |
| 293 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastResultPtr", .{}); | |
| 297 | return mod.fail(scope, inst.base.src, "TODO implement zir_sema.bitCastResultPtr", .{}); | |
| 294 | 298 | } |
| 295 | 299 | |
| 296 | 300 | fn analyzeInstCoerceResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| ... | ... | @@ -318,21 +322,12 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr |
| 318 | 322 | return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); |
| 319 | 323 | } |
| 320 | 324 | |
| 321 | fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 325 | fn ref(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 322 | 326 | const tracy = trace(@src()); |
| 323 | 327 | defer tracy.end(); |
| 324 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | |
| 325 | const ptr_type = try mod.simplePtrType(scope, inst.base.src, operand.ty, false, .One); | |
| 326 | ||
| 327 | if (operand.value()) |val| { | |
| 328 | return mod.constInst(scope, inst.base.src, .{ | |
| 329 | .ty = ptr_type, | |
| 330 | .val = try Value.Tag.ref_val.create(scope.arena(), val), | |
| 331 | }); | |
| 332 | } | |
| 333 | 328 | |
| 334 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); | |
| 335 | return mod.addUnOp(b, inst.base.src, ptr_type, .ref, operand); | |
| 329 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | |
| 330 | return mod.analyzeRef(scope, inst.base.src, operand); | |
| 336 | 331 | } |
| 337 | 332 | |
| 338 | 333 | fn analyzeInstRetType(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { |
| ... | ... | @@ -364,19 +359,34 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst. |
| 364 | 359 | } |
| 365 | 360 | } |
| 366 | 361 | |
| 367 | fn analyzeInstEnsureIndexable(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 362 | fn indexablePtrLen(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 368 | 363 | const tracy = trace(@src()); |
| 369 | 364 | defer tracy.end(); |
| 370 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | |
| 371 | const elem_ty = operand.ty.elemType(); | |
| 372 | if (elem_ty.isIndexable()) { | |
| 373 | return mod.constVoid(scope, operand.src); | |
| 374 | } else { | |
| 375 | // TODO error notes | |
| 376 | // error: type '{}' does not support indexing | |
| 377 | // note: for loop operand must be an array, a slice or a tuple | |
| 378 | return mod.fail(scope, operand.src, "for loop operand must be an array, a slice or a tuple", .{}); | |
| 365 | ||
| 366 | const array_ptr = try resolveInst(mod, scope, inst.positionals.operand); | |
| 367 | const elem_ty = array_ptr.ty.elemType(); | |
| 368 | if (!elem_ty.isIndexable()) { | |
| 369 | const msg = msg: { | |
| 370 | const msg = try mod.errMsg( | |
| 371 | scope, | |
| 372 | inst.base.src, | |
| 373 | "type '{}' does not support indexing", | |
| 374 | .{elem_ty}, | |
| 375 | ); | |
| 376 | errdefer msg.destroy(mod.gpa); | |
| 377 | try mod.errNote( | |
| 378 | scope, | |
| 379 | inst.base.src, | |
| 380 | msg, | |
| 381 | "for loop operand must be an array, slice, tuple, or vector", | |
| 382 | .{}, | |
| 383 | ); | |
| 384 | break :msg msg; | |
| 385 | }; | |
| 386 | return mod.failWithOwnedErrorMsg(scope, msg); | |
| 379 | 387 | } |
| 388 | const result_ptr = try mod.namedFieldPtr(scope, inst.base.src, array_ptr, "len", inst.base.src); | |
| 389 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); | |
| 380 | 390 | } |
| 381 | 391 | |
| 382 | 392 | fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| ... | ... | @@ -826,21 +836,19 @@ fn analyzeInstDeclRefStr(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr |
| 826 | 836 | return mod.analyzeDeclRefByName(scope, inst.base.src, decl_name); |
| 827 | 837 | } |
| 828 | 838 | |
| 829 | fn analyzeInstDeclRef(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst { | |
| 839 | fn declRef(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst { | |
| 830 | 840 | const tracy = trace(@src()); |
| 831 | 841 | defer tracy.end(); |
| 832 | 842 | return mod.analyzeDeclRef(scope, inst.base.src, inst.positionals.decl); |
| 833 | 843 | } |
| 834 | 844 | |
| 835 | fn analyzeInstDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Inst { | |
| 845 | fn declVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Inst { | |
| 836 | 846 | const tracy = trace(@src()); |
| 837 | 847 | defer tracy.end(); |
| 838 | const decl_ref = try mod.analyzeDeclRef(scope, inst.base.src, inst.positionals.decl); | |
| 839 | // TODO look into avoiding the call to analyzeDeref here | |
| 840 | return mod.analyzeDeref(scope, inst.base.src, decl_ref, inst.base.src); | |
| 848 | return mod.analyzeDeclVal(scope, inst.base.src, inst.positionals.decl); | |
| 841 | 849 | } |
| 842 | 850 | |
| 843 | fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { | |
| 851 | fn call(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { | |
| 844 | 852 | const tracy = trace(@src()); |
| 845 | 853 | defer tracy.end(); |
| 846 | 854 | |
| ... | ... | @@ -1093,7 +1101,7 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In |
| 1093 | 1101 | .val = Value.initPayload(&payload.base), |
| 1094 | 1102 | }); |
| 1095 | 1103 | payload.data.decl = new_decl; |
| 1096 | return mod.analyzeDeclRef(scope, inst.base.src, new_decl); | |
| 1104 | return mod.analyzeDeclVal(scope, inst.base.src, new_decl); | |
| 1097 | 1105 | } |
| 1098 | 1106 | |
| 1099 | 1107 | fn analyzeInstMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| ... | ... | @@ -1293,108 +1301,46 @@ fn analyzeInstPtrToInt(mod: *Module, scope: *Scope, ptrtoint: *zir.Inst.UnOp) In |
| 1293 | 1301 | return mod.addUnOp(b, ptrtoint.base.src, ty, .ptrtoint, ptr); |
| 1294 | 1302 | } |
| 1295 | 1303 | |
| 1296 | fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr) InnerError!*Inst { | |
| 1304 | fn fieldVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst { | |
| 1297 | 1305 | const tracy = trace(@src()); |
| 1298 | 1306 | defer tracy.end(); |
| 1299 | const object_ptr = try resolveInst(mod, scope, fieldptr.positionals.object_ptr); | |
| 1300 | const field_name = try resolveConstString(mod, scope, fieldptr.positionals.field_name); | |
| 1301 | 1307 | |
| 1302 | const elem_ty = switch (object_ptr.ty.zigTypeTag()) { | |
| 1303 | .Pointer => object_ptr.ty.elemType(), | |
| 1304 | else => return mod.fail(scope, fieldptr.positionals.object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}), | |
| 1305 | }; | |
| 1306 | switch (elem_ty.zigTypeTag()) { | |
| 1307 | .Array => { | |
| 1308 | if (mem.eql(u8, field_name, "len")) { | |
| 1309 | return mod.constInst(scope, fieldptr.base.src, .{ | |
| 1310 | .ty = Type.initTag(.single_const_pointer_to_comptime_int), | |
| 1311 | .val = try Value.Tag.ref_val.create( | |
| 1312 | scope.arena(), | |
| 1313 | try Value.Tag.int_u64.create(scope.arena(), elem_ty.arrayLen()), | |
| 1314 | ), | |
| 1315 | }); | |
| 1316 | } else { | |
| 1317 | return mod.fail( | |
| 1318 | scope, | |
| 1319 | fieldptr.positionals.field_name.src, | |
| 1320 | "no member named '{s}' in '{}'", | |
| 1321 | .{ field_name, elem_ty }, | |
| 1322 | ); | |
| 1323 | } | |
| 1324 | }, | |
| 1325 | .Pointer => { | |
| 1326 | const ptr_child = elem_ty.elemType(); | |
| 1327 | switch (ptr_child.zigTypeTag()) { | |
| 1328 | .Array => { | |
| 1329 | if (mem.eql(u8, field_name, "len")) { | |
| 1330 | return mod.constInst(scope, fieldptr.base.src, .{ | |
| 1331 | .ty = Type.initTag(.single_const_pointer_to_comptime_int), | |
| 1332 | .val = try Value.Tag.ref_val.create( | |
| 1333 | scope.arena(), | |
| 1334 | try Value.Tag.int_u64.create(scope.arena(), ptr_child.arrayLen()), | |
| 1335 | ), | |
| 1336 | }); | |
| 1337 | } else { | |
| 1338 | return mod.fail( | |
| 1339 | scope, | |
| 1340 | fieldptr.positionals.field_name.src, | |
| 1341 | "no member named '{s}' in '{}'", | |
| 1342 | .{ field_name, elem_ty }, | |
| 1343 | ); | |
| 1344 | } | |
| 1345 | }, | |
| 1346 | else => {}, | |
| 1347 | } | |
| 1348 | }, | |
| 1349 | .Type => { | |
| 1350 | _ = try mod.resolveConstValue(scope, object_ptr); | |
| 1351 | const result = try mod.analyzeDeref(scope, fieldptr.base.src, object_ptr, object_ptr.src); | |
| 1352 | const val = result.value().?; | |
| 1353 | const child_type = try val.toType(scope.arena()); | |
| 1354 | switch (child_type.zigTypeTag()) { | |
| 1355 | .ErrorSet => { | |
| 1356 | // TODO resolve inferred error sets | |
| 1357 | const entry = if (val.castTag(.error_set)) |payload| | |
| 1358 | (payload.data.fields.getEntry(field_name) orelse | |
| 1359 | return mod.fail(scope, fieldptr.base.src, "no error named '{s}' in '{}'", .{ field_name, child_type })).* | |
| 1360 | else | |
| 1361 | try mod.getErrorValue(field_name); | |
| 1362 | ||
| 1363 | const result_type = if (child_type.tag() == .anyerror) | |
| 1364 | try Type.Tag.error_set_single.create(scope.arena(), entry.key) | |
| 1365 | else | |
| 1366 | child_type; | |
| 1367 | ||
| 1368 | return mod.constInst(scope, fieldptr.base.src, .{ | |
| 1369 | .ty = try mod.simplePtrType(scope, fieldptr.base.src, result_type, false, .One), | |
| 1370 | .val = try Value.Tag.ref_val.create( | |
| 1371 | scope.arena(), | |
| 1372 | try Value.Tag.@"error".create(scope.arena(), .{ | |
| 1373 | .name = entry.key, | |
| 1374 | .value = entry.value, | |
| 1375 | }), | |
| 1376 | ), | |
| 1377 | }); | |
| 1378 | }, | |
| 1379 | .Struct => { | |
| 1380 | const container_scope = child_type.getContainerScope(); | |
| 1381 | if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| { | |
| 1382 | // TODO if !decl.is_pub and inDifferentFiles() "{} is private" | |
| 1383 | return mod.analyzeDeclRef(scope, fieldptr.base.src, decl); | |
| 1384 | } | |
| 1308 | const object = try resolveInst(mod, scope, inst.positionals.object); | |
| 1309 | const field_name = inst.positionals.field_name; | |
| 1310 | const object_ptr = try mod.analyzeRef(scope, inst.base.src, object); | |
| 1311 | const result_ptr = try mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, inst.base.src); | |
| 1312 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); | |
| 1313 | } | |
| 1385 | 1314 | |
| 1386 | if (container_scope.file_scope == mod.root_scope) { | |
| 1387 | return mod.fail(scope, fieldptr.base.src, "root source file has no member called '{s}'", .{field_name}); | |
| 1388 | } else { | |
| 1389 | return mod.fail(scope, fieldptr.base.src, "container '{}' has no member called '{s}'", .{ child_type, field_name }); | |
| 1390 | } | |
| 1391 | }, | |
| 1392 | else => return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{child_type}), | |
| 1393 | } | |
| 1394 | }, | |
| 1395 | else => {}, | |
| 1396 | } | |
| 1397 | return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{elem_ty}); | |
| 1315 | fn fieldPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst { | |
| 1316 | const tracy = trace(@src()); | |
| 1317 | defer tracy.end(); | |
| 1318 | ||
| 1319 | const object_ptr = try resolveInst(mod, scope, inst.positionals.object); | |
| 1320 | const field_name = inst.positionals.field_name; | |
| 1321 | return mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, inst.base.src); | |
| 1322 | } | |
| 1323 | ||
| 1324 | fn fieldValNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerError!*Inst { | |
| 1325 | const tracy = trace(@src()); | |
| 1326 | defer tracy.end(); | |
| 1327 | ||
| 1328 | const object = try resolveInst(mod, scope, inst.positionals.object); | |
| 1329 | const field_name = try resolveConstString(mod, scope, inst.positionals.field_name); | |
| 1330 | const fsrc = inst.positionals.field_name.src; | |
| 1331 | const object_ptr = try mod.analyzeRef(scope, inst.base.src, object); | |
| 1332 | const result_ptr = try mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, fsrc); | |
| 1333 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); | |
| 1334 | } | |
| 1335 | ||
| 1336 | fn fieldPtrNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerError!*Inst { | |
| 1337 | const tracy = trace(@src()); | |
| 1338 | defer tracy.end(); | |
| 1339 | ||
| 1340 | const object_ptr = try resolveInst(mod, scope, inst.positionals.object); | |
| 1341 | const field_name = try resolveConstString(mod, scope, inst.positionals.field_name); | |
| 1342 | const fsrc = inst.positionals.field_name.src; | |
| 1343 | return mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, fsrc); | |
| 1398 | 1344 | } |
| 1399 | 1345 | |
| 1400 | 1346 | fn analyzeInstIntCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| ... | ... | @@ -1481,42 +1427,24 @@ fn analyzeInstFloatCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inne |
| 1481 | 1427 | return mod.fail(scope, inst.base.src, "TODO implement analyze widen or shorten float", .{}); |
| 1482 | 1428 | } |
| 1483 | 1429 | |
| 1484 | fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) InnerError!*Inst { | |
| 1430 | fn elemVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst { | |
| 1485 | 1431 | const tracy = trace(@src()); |
| 1486 | 1432 | defer tracy.end(); |
| 1487 | const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr); | |
| 1488 | const uncasted_index = try resolveInst(mod, scope, inst.positionals.index); | |
| 1489 | const elem_index = try mod.coerce(scope, Type.initTag(.usize), uncasted_index); | |
| 1490 | 1433 | |
| 1491 | const elem_ty = switch (array_ptr.ty.zigTypeTag()) { | |
| 1492 | .Pointer => array_ptr.ty.elemType(), | |
| 1493 | else => return mod.fail(scope, inst.positionals.array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}), | |
| 1494 | }; | |
| 1495 | if (!elem_ty.isIndexable()) { | |
| 1496 | return mod.fail(scope, inst.base.src, "array access of non-array type '{}'", .{elem_ty}); | |
| 1497 | } | |
| 1498 | ||
| 1499 | if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) { | |
| 1500 | // we have to deref the ptr operand to get the actual array pointer | |
| 1501 | const array_ptr_deref = try mod.analyzeDeref(scope, inst.base.src, array_ptr, inst.positionals.array_ptr.src); | |
| 1502 | if (array_ptr_deref.value()) |array_ptr_val| { | |
| 1503 | if (elem_index.value()) |index_val| { | |
| 1504 | // Both array pointer and index are compile-time known. | |
| 1505 | const index_u64 = index_val.toUnsignedInt(); | |
| 1506 | // @intCast here because it would have been impossible to construct a value that | |
| 1507 | // required a larger index. | |
| 1508 | const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64)); | |
| 1509 | const pointee_type = elem_ty.elemType().elemType(); | |
| 1434 | const array = try resolveInst(mod, scope, inst.positionals.array); | |
| 1435 | const array_ptr = try mod.analyzeRef(scope, inst.base.src, array); | |
| 1436 | const elem_index = try resolveInst(mod, scope, inst.positionals.index); | |
| 1437 | const result_ptr = try mod.elemPtr(scope, inst.base.src, array_ptr, elem_index); | |
| 1438 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); | |
| 1439 | } | |
| 1510 | 1440 | |
| 1511 | return mod.constInst(scope, inst.base.src, .{ | |
| 1512 | .ty = try Type.Tag.single_const_pointer.create(scope.arena(), pointee_type), | |
| 1513 | .val = elem_ptr, | |
| 1514 | }); | |
| 1515 | } | |
| 1516 | } | |
| 1517 | } | |
| 1441 | fn elemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst { | |
| 1442 | const tracy = trace(@src()); | |
| 1443 | defer tracy.end(); | |
| 1518 | 1444 | |
| 1519 | return mod.fail(scope, inst.base.src, "TODO implement more analyze elemptr", .{}); | |
| 1445 | const array_ptr = try resolveInst(mod, scope, inst.positionals.array); | |
| 1446 | const elem_index = try resolveInst(mod, scope, inst.positionals.index); | |
| 1447 | return mod.elemPtr(scope, inst.base.src, array_ptr, elem_index); | |
| 1520 | 1448 | } |
| 1521 | 1449 | |
| 1522 | 1450 | fn analyzeInstSlice(mod: *Module, scope: *Scope, inst: *zir.Inst.Slice) InnerError!*Inst { |
test/stage2/aarch64.zig+1-1| ... | ... | @@ -80,7 +80,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 80 | 80 | } |
| 81 | 81 | |
| 82 | 82 | { |
| 83 | var case = ctx.exe("hello world", linux_aarch64); | |
| 83 | var case = ctx.exe("linux_aarch64 hello world", linux_aarch64); | |
| 84 | 84 | // Regular old hello world |
| 85 | 85 | case.addCompareOutput( |
| 86 | 86 | \\export fn _start() noreturn { |
test/stage2/arm.zig+1-1| ... | ... | @@ -8,7 +8,7 @@ const linux_arm = std.zig.CrossTarget{ |
| 8 | 8 | |
| 9 | 9 | pub fn addCases(ctx: *TestContext) !void { |
| 10 | 10 | { |
| 11 | var case = ctx.exe("hello world", linux_arm); | |
| 11 | var case = ctx.exe("linux_arm hello world", linux_arm); | |
| 12 | 12 | // Regular old hello world |
| 13 | 13 | case.addCompareOutput( |
| 14 | 14 | \\export fn _start() noreturn { |
test/stage2/llvm.zig+1-1| ... | ... | @@ -29,7 +29,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | 31 | { |
| 32 | var case = ctx.exeUsingLlvmBackend("hello world", linux_x64); | |
| 32 | var case = ctx.exeUsingLlvmBackend("llvm hello world", linux_x64); | |
| 33 | 33 | |
| 34 | 34 | case.addCompareOutput( |
| 35 | 35 | \\extern fn puts(s: [*:0]const u8) c_int; |
test/stage2/test.zig+1-1| ... | ... | @@ -231,7 +231,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 231 | 231 | } |
| 232 | 232 | |
| 233 | 233 | { |
| 234 | var case = ctx.exe("hello world", linux_riscv64); | |
| 234 | var case = ctx.exe("riscv64 hello world", linux_riscv64); | |
| 235 | 235 | // Regular old hello world |
| 236 | 236 | case.addCompareOutput( |
| 237 | 237 | \\export fn _start() noreturn { |