| 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,6 +2357,11 @@ pub fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*De |
| 2357 | return self.decl_table.get(name_hash); | 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 | pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst { | 2365 | pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst { |
| 2361 | const scope_decl = scope.ownerDecl().?; | 2366 | const scope_decl = scope.ownerDecl().?; |
| 2362 | try self.declareDeclDependency(scope_decl, decl); | 2367 | try self.declareDeclDependency(scope_decl, decl); |
| ... | @@ -2408,6 +2413,20 @@ fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) Inner | ... | @@ -2408,6 +2413,20 @@ fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) Inner |
| 2408 | return &inst.base; | 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 | pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst { | 2430 | pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst { |
| 2412 | const elem_ty = switch (ptr.ty.zigTypeTag()) { | 2431 | const elem_ty = switch (ptr.ty.zigTypeTag()) { |
| 2413 | .Pointer => ptr.ty.elemType(), | 2432 | .Pointer => ptr.ty.elemType(), |
| ... | @@ -3543,3 +3562,147 @@ pub fn emitBackwardBranch(mod: *Module, block: *Scope.Block, src: usize) !void { | ... | @@ -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,7 +278,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 278 | .ErrorUnion => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.ErrorUnion).?, .error_union_type)), | 278 | .ErrorUnion => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.ErrorUnion).?, .error_union_type)), |
| 279 | .MergeErrorSets => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.MergeErrorSets).?, .merge_error_sets)), | 279 | .MergeErrorSets => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.MergeErrorSets).?, .merge_error_sets)), |
| 280 | .AnyFrameType => return rlWrap(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)), | 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 | .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), | 282 | .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), |
| 283 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), | 283 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), |
| 284 | .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?), | 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,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 | const tree = scope.tree(); | 1111 | const tree = scope.tree(); |
| 1112 | const src = tree.token_locs[node.error_token].start; | 1112 | const src = tree.token_locs[node.error_token].start; |
| 1113 | const decls = node.decls(); | 1113 | const decls = node.decls(); |
| ... | @@ -1118,9 +1118,7 @@ fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Erro | ... | @@ -1118,9 +1118,7 @@ fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Erro |
| 1118 | fields[i] = try mod.identifierTokenString(scope, tag.name_token); | 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 | 1121 | return addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{}); |
| 1122 | // TODO remove all callsites to rlWrapPtr | ||
| 1123 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{})); | ||
| 1124 | } | 1122 | } |
| 1125 | 1123 | ||
| 1126 | fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst { | 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,35 +1297,72 @@ fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: as |
| 1299 | return mem.eql(u8, ident_name_1, ident_name_2); | 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 | const tree = scope.tree(); | 1301 | const tree = scope.tree(); |
| 1304 | const src = tree.token_locs[node.token].start; | 1302 | const src = tree.token_locs[node.op_token].start; |
| 1305 | 1303 | // TODO custom AST node for field access so that we don't have to go through a node cast here | |
| 1306 | const ident_name = try mod.identifierTokenString(scope, node.token); | 1304 | const field_name = try mod.identifierTokenString(scope, node.rhs.castTag(.Identifier).?.token); |
| 1307 | 1305 | if (rl == .ref) { | |
| 1308 | return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = ident_name }, .{}); | 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 | const tree = scope.tree(); | 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); | 1329 | const string_type = try addZIRInstConst(mod, scope, src, .{ |
| 1316 | const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?); | 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 | 1335 | if (rl == .ref) { |
| 1319 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{})); | 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 | fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ArrayAccess) InnerError!*zir.Inst { | 1347 | fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ArrayAccess) InnerError!*zir.Inst { |
| 1323 | const tree = scope.tree(); | 1348 | const tree = scope.tree(); |
| 1324 | const src = tree.token_locs[node.rtoken].start; | 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); | 1356 | if (rl == .ref) { |
| 1327 | const index = try expr(mod, scope, .none, node.index_expr); | 1357 | return addZirInstTag(mod, scope, src, .elem_ptr, .{ |
| 1328 | 1358 | .array = try expr(mod, scope, .ref, node.lhs), | |
| 1329 | // TODO remove all callsites to rlWrapPtr | 1359 | .index = try expr(mod, scope, index_rl, node.index_expr), |
| 1330 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ElemPtr, .{ .array_ptr = array_ptr, .index = index }, .{})); | 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 | fn sliceExpr(mod: *Module, scope: *Scope, node: *ast.Node.Slice) InnerError!*zir.Inst { | 1368 | fn sliceExpr(mod: *Module, scope: *Scope, node: *ast.Node.Slice) InnerError!*zir.Inst { |
| ... | @@ -1819,12 +1854,8 @@ fn forExpr( | ... | @@ -1819,12 +1854,8 @@ fn forExpr( |
| 1819 | break :blk index_ptr; | 1854 | break :blk index_ptr; |
| 1820 | }; | 1855 | }; |
| 1821 | const array_ptr = try expr(mod, &for_scope.base, .ref, for_node.array_expr); | 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 | const cond_src = tree.token_locs[for_node.array_expr.firstToken()].start; | 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, .{ | 1858 | const len = try addZIRUnOp(mod, &for_scope.base, cond_src, .indexable_ptr_len, array_ptr); |
| 1825 | .object_ptr = array_ptr, | ||
| 1826 | .field_name = try addZIRInst(mod, &for_scope.base, cond_src, zir.Inst.Str, .{ .bytes = "len" }, .{}), | ||
| 1827 | }, .{}); | ||
| 1828 | 1859 | ||
| 1829 | var loop_scope: Scope.GenZIR = .{ | 1860 | var loop_scope: Scope.GenZIR = .{ |
| 1830 | .parent = &for_scope.base, | 1861 | .parent = &for_scope.base, |
| ... | @@ -1845,7 +1876,6 @@ fn forExpr( | ... | @@ -1845,7 +1876,6 @@ fn forExpr( |
| 1845 | 1876 | ||
| 1846 | // check condition i < array_expr.len | 1877 | // check condition i < array_expr.len |
| 1847 | const index = try addZIRUnOp(mod, &cond_scope.base, cond_src, .deref, index_ptr); | 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 | const cond = try addZIRBinOp(mod, &cond_scope.base, cond_src, .cmp_lt, index, len); | 1879 | const cond = try addZIRBinOp(mod, &cond_scope.base, cond_src, .cmp_lt, index, len); |
| 1850 | 1880 | ||
| 1851 | const condbr = try addZIRInstSpecial(mod, &cond_scope.base, for_src, zir.Inst.CondBr, .{ | 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,8 +2358,9 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo |
| 2328 | .local_ptr => { | 2358 | .local_ptr => { |
| 2329 | const local_ptr = s.cast(Scope.LocalPtr).?; | 2359 | const local_ptr = s.cast(Scope.LocalPtr).?; |
| 2330 | if (mem.eql(u8, local_ptr.name, ident_name)) { | 2360 | if (mem.eql(u8, local_ptr.name, ident_name)) { |
| 2331 | // TODO remove all callsites to rlWrapPtr | 2361 | if (rl == .ref) return local_ptr.ptr; |
| 2332 | return rlWrapPtr(mod, scope, rl, 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 | s = local_ptr.parent; | 2365 | s = local_ptr.parent; |
| 2335 | }, | 2366 | }, |
| ... | @@ -2747,6 +2778,8 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built | ... | @@ -2747,6 +2778,8 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built |
| 2747 | return setEvalBranchQuota(mod, scope, call); | 2778 | return setEvalBranchQuota(mod, scope, call); |
| 2748 | } else if (mem.eql(u8, builtin_name, "@compileLog")) { | 2779 | } else if (mem.eql(u8, builtin_name, "@compileLog")) { |
| 2749 | return compileLog(mod, scope, call); | 2780 | return compileLog(mod, scope, call); |
| 2781 | } else if (mem.eql(u8, builtin_name, "@field")) { | ||
| 2782 | return namedField(mod, scope, rl, call); | ||
| 2750 | } else { | 2783 | } else { |
| 2751 | return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{s}'", .{builtin_name}); | 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,6 +3152,28 @@ fn rlWrapPtr(mod: *Module, scope: *Scope, rl: ResultLoc, ptr: *zir.Inst) InnerEr |
| 3119 | return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, ptr.src, .deref, ptr)); | 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 | pub fn addZIRInstSpecial( | 3177 | pub fn addZIRInstSpecial( |
| 3123 | mod: *Module, | 3178 | mod: *Module, |
| 3124 | scope: *Scope, | 3179 | scope: *Scope, |
src/zir.zig+43-17| ... | @@ -47,6 +47,10 @@ pub const Inst = struct { | ... | @@ -47,6 +47,10 @@ pub const Inst = struct { |
| 47 | array_type, | 47 | array_type, |
| 48 | /// Create an array type with sentinel | 48 | /// Create an array type with sentinel |
| 49 | array_type_sentinel, | 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 | /// Function parameter value. These must be first in a function's main block, | 54 | /// Function parameter value. These must be first in a function's main block, |
| 51 | /// in respective order with the parameters. | 55 | /// in respective order with the parameters. |
| 52 | arg, | 56 | arg, |
| ... | @@ -142,13 +146,13 @@ pub const Inst = struct { | ... | @@ -142,13 +146,13 @@ pub const Inst = struct { |
| 142 | div, | 146 | div, |
| 143 | /// Given a pointer to an array, slice, or pointer, returns a pointer to the element at | 147 | /// Given a pointer to an array, slice, or pointer, returns a pointer to the element at |
| 144 | /// the provided index. | 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 | /// Emits a compile error if the operand is not `void`. | 152 | /// Emits a compile error if the operand is not `void`. |
| 147 | ensure_result_used, | 153 | ensure_result_used, |
| 148 | /// Emits a compile error if an error is ignored. | 154 | /// Emits a compile error if an error is ignored. |
| 149 | ensure_result_non_error, | 155 | ensure_result_non_error, |
| 150 | /// Emits a compile error if operand cannot be indexed. | ||
| 151 | ensure_indexable, | ||
| 152 | /// Create a `E!T` type. | 156 | /// Create a `E!T` type. |
| 153 | error_union_type, | 157 | error_union_type, |
| 154 | /// Create an error set. | 158 | /// Create an error set. |
| ... | @@ -156,8 +160,17 @@ pub const Inst = struct { | ... | @@ -156,8 +160,17 @@ pub const Inst = struct { |
| 156 | /// Export the provided Decl as the provided name in the compilation's output object file. | 160 | /// Export the provided Decl as the provided name in the compilation's output object file. |
| 157 | @"export", | 161 | @"export", |
| 158 | /// Given a pointer to a struct or object that contains virtual fields, returns a pointer | 162 | /// Given a pointer to a struct or object that contains virtual fields, returns a pointer |
| 159 | /// to the named field. | 163 | /// to the named field. The field name is a []const u8. Used by a.b syntax. |
| 160 | fieldptr, | 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 | /// Convert a larger float type to any other float type, possibly causing a loss of precision. | 174 | /// Convert a larger float type to any other float type, possibly causing a loss of precision. |
| 162 | floatcast, | 175 | floatcast, |
| 163 | /// Declare a function body. | 176 | /// Declare a function body. |
| ... | @@ -361,7 +374,6 @@ pub const Inst = struct { | ... | @@ -361,7 +374,6 @@ pub const Inst = struct { |
| 361 | .ptrtoint, | 374 | .ptrtoint, |
| 362 | .ensure_result_used, | 375 | .ensure_result_used, |
| 363 | .ensure_result_non_error, | 376 | .ensure_result_non_error, |
| 364 | .ensure_indexable, | ||
| 365 | .bitcast_result_ptr, | 377 | .bitcast_result_ptr, |
| 366 | .ref, | 378 | .ref, |
| 367 | .bitcast_ref, | 379 | .bitcast_ref, |
| ... | @@ -391,6 +403,7 @@ pub const Inst = struct { | ... | @@ -391,6 +403,7 @@ pub const Inst = struct { |
| 391 | .bitnot, | 403 | .bitnot, |
| 392 | .import, | 404 | .import, |
| 393 | .set_eval_branch_quota, | 405 | .set_eval_branch_quota, |
| 406 | .indexable_ptr_len, | ||
| 394 | => UnOp, | 407 | => UnOp, |
| 395 | 408 | ||
| 396 | .add, | 409 | .add, |
| ... | @@ -452,14 +465,15 @@ pub const Inst = struct { | ... | @@ -452,14 +465,15 @@ pub const Inst = struct { |
| 452 | .str => Str, | 465 | .str => Str, |
| 453 | .int => Int, | 466 | .int => Int, |
| 454 | .inttype => IntType, | 467 | .inttype => IntType, |
| 455 | .fieldptr => FieldPtr, | 468 | .field_ptr, .field_val => Field, |
| 469 | .field_ptr_named, .field_val_named => FieldNamed, | ||
| 456 | .@"asm" => Asm, | 470 | .@"asm" => Asm, |
| 457 | .@"fn" => Fn, | 471 | .@"fn" => Fn, |
| 458 | .@"export" => Export, | 472 | .@"export" => Export, |
| 459 | .param_type => ParamType, | 473 | .param_type => ParamType, |
| 460 | .primitive => Primitive, | 474 | .primitive => Primitive, |
| 461 | .fntype => FnType, | 475 | .fntype => FnType, |
| 462 | .elemptr => ElemPtr, | 476 | .elem_ptr, .elem_val => Elem, |
| 463 | .condbr => CondBr, | 477 | .condbr => CondBr, |
| 464 | .ptr_type => PtrType, | 478 | .ptr_type => PtrType, |
| 465 | .enum_literal => EnumLiteral, | 479 | .enum_literal => EnumLiteral, |
| ... | @@ -490,6 +504,7 @@ pub const Inst = struct { | ... | @@ -490,6 +504,7 @@ pub const Inst = struct { |
| 490 | .array_mul, | 504 | .array_mul, |
| 491 | .array_type, | 505 | .array_type, |
| 492 | .array_type_sentinel, | 506 | .array_type_sentinel, |
| 507 | .indexable_ptr_len, | ||
| 493 | .arg, | 508 | .arg, |
| 494 | .as, | 509 | .as, |
| 495 | .@"asm", | 510 | .@"asm", |
| ... | @@ -523,13 +538,16 @@ pub const Inst = struct { | ... | @@ -523,13 +538,16 @@ pub const Inst = struct { |
| 523 | .declval, | 538 | .declval, |
| 524 | .deref, | 539 | .deref, |
| 525 | .div, | 540 | .div, |
| 526 | .elemptr, | 541 | .elem_ptr, |
| 542 | .elem_val, | ||
| 527 | .ensure_result_used, | 543 | .ensure_result_used, |
| 528 | .ensure_result_non_error, | 544 | .ensure_result_non_error, |
| 529 | .ensure_indexable, | ||
| 530 | .@"export", | 545 | .@"export", |
| 531 | .floatcast, | 546 | .floatcast, |
| 532 | .fieldptr, | 547 | .field_ptr, |
| 548 | .field_val, | ||
| 549 | .field_ptr_named, | ||
| 550 | .field_val_named, | ||
| 533 | .@"fn", | 551 | .@"fn", |
| 534 | .fntype, | 552 | .fntype, |
| 535 | .int, | 553 | .int, |
| ... | @@ -823,12 +841,21 @@ pub const Inst = struct { | ... | @@ -823,12 +841,21 @@ pub const Inst = struct { |
| 823 | kw_args: struct {}, | 841 | kw_args: struct {}, |
| 824 | }; | 842 | }; |
| 825 | 843 | ||
| 826 | pub const FieldPtr = struct { | 844 | pub const Field = struct { |
| 827 | pub const base_tag = Tag.fieldptr; | ||
| 828 | base: Inst, | 845 | base: Inst, |
| 829 | 846 | ||
| 830 | positionals: struct { | 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 | field_name: *Inst, | 859 | field_name: *Inst, |
| 833 | }, | 860 | }, |
| 834 | kw_args: struct {}, | 861 | kw_args: struct {}, |
| ... | @@ -1000,12 +1027,11 @@ pub const Inst = struct { | ... | @@ -1000,12 +1027,11 @@ pub const Inst = struct { |
| 1000 | }; | 1027 | }; |
| 1001 | }; | 1028 | }; |
| 1002 | 1029 | ||
| 1003 | pub const ElemPtr = struct { | 1030 | pub const Elem = struct { |
| 1004 | pub const base_tag = Tag.elemptr; | ||
| 1005 | base: Inst, | 1031 | base: Inst, |
| 1006 | 1032 | ||
| 1007 | positionals: struct { | 1033 | positionals: struct { |
| 1008 | array_ptr: *Inst, | 1034 | array: *Inst, |
| 1009 | index: *Inst, | 1035 | index: *Inst, |
| 1010 | }, | 1036 | }, |
| 1011 | kw_args: struct {}, | 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,8 +43,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 43 | .inferred_alloc_mut, | 43 | .inferred_alloc_mut, |
| 44 | ), | 44 | ), |
| 45 | .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?), | 45 | .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?), |
| 46 | .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?), | 46 | .bitcast_ref => return bitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?), |
| 47 | .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?), | 47 | .bitcast_result_ptr => return bitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?), |
| 48 | .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?, false), | 48 | .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?, false), |
| 49 | .block_comptime => return analyzeInstBlock(mod, scope, old_inst.castTag(.block_comptime).?, true), | 49 | .block_comptime => return analyzeInstBlock(mod, scope, old_inst.castTag(.block_comptime).?, true), |
| 50 | .block_flat => return analyzeInstBlockFlat(mod, scope, old_inst.castTag(.block_flat).?, false), | 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,7 +52,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 52 | .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?), | 52 | .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?), |
| 53 | .breakpoint => return analyzeInstBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?), | 53 | .breakpoint => return analyzeInstBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?), |
| 54 | .breakvoid => return analyzeInstBreakVoid(mod, scope, old_inst.castTag(.breakvoid).?), | 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 | .coerce_result_block_ptr => return analyzeInstCoerceResultBlockPtr(mod, scope, old_inst.castTag(.coerce_result_block_ptr).?), | 56 | .coerce_result_block_ptr => return analyzeInstCoerceResultBlockPtr(mod, scope, old_inst.castTag(.coerce_result_block_ptr).?), |
| 57 | .coerce_result_ptr => return analyzeInstCoerceResultPtr(mod, scope, old_inst.castTag(.coerce_result_ptr).?), | 57 | .coerce_result_ptr => return analyzeInstCoerceResultPtr(mod, scope, old_inst.castTag(.coerce_result_ptr).?), |
| 58 | .coerce_to_ptr_elem => return analyzeInstCoerceToPtrElem(mod, scope, old_inst.castTag(.coerce_to_ptr_elem).?), | 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,13 +60,13 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 60 | .compilelog => return analyzeInstCompileLog(mod, scope, old_inst.castTag(.compilelog).?), | 60 | .compilelog => return analyzeInstCompileLog(mod, scope, old_inst.castTag(.compilelog).?), |
| 61 | .@"const" => return analyzeInstConst(mod, scope, old_inst.castTag(.@"const").?), | 61 | .@"const" => return analyzeInstConst(mod, scope, old_inst.castTag(.@"const").?), |
| 62 | .dbg_stmt => return analyzeInstDbgStmt(mod, scope, old_inst.castTag(.dbg_stmt).?), | 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 | .declref_str => return analyzeInstDeclRefStr(mod, scope, old_inst.castTag(.declref_str).?), | 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 | .ensure_result_used => return analyzeInstEnsureResultUsed(mod, scope, old_inst.castTag(.ensure_result_used).?), | 66 | .ensure_result_used => return analyzeInstEnsureResultUsed(mod, scope, old_inst.castTag(.ensure_result_used).?), |
| 67 | .ensure_result_non_error => return analyzeInstEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?), | 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).?), | 68 | .indexable_ptr_len => return indexablePtrLen(mod, scope, old_inst.castTag(.indexable_ptr_len).?), |
| 69 | .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?), | 69 | .ref => return ref(mod, scope, old_inst.castTag(.ref).?), |
| 70 | .resolve_inferred_alloc => return analyzeInstResolveInferredAlloc(mod, scope, old_inst.castTag(.resolve_inferred_alloc).?), | 70 | .resolve_inferred_alloc => return analyzeInstResolveInferredAlloc(mod, scope, old_inst.castTag(.resolve_inferred_alloc).?), |
| 71 | .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?), | 71 | .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?), |
| 72 | .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?), | 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,7 +88,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 88 | .loop => return analyzeInstLoop(mod, scope, old_inst.castTag(.loop).?), | 88 | .loop => return analyzeInstLoop(mod, scope, old_inst.castTag(.loop).?), |
| 89 | .param_type => return analyzeInstParamType(mod, scope, old_inst.castTag(.param_type).?), | 89 | .param_type => return analyzeInstParamType(mod, scope, old_inst.castTag(.param_type).?), |
| 90 | .ptrtoint => return analyzeInstPtrToInt(mod, scope, old_inst.castTag(.ptrtoint).?), | 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 | .deref => return analyzeInstDeref(mod, scope, old_inst.castTag(.deref).?), | 95 | .deref => return analyzeInstDeref(mod, scope, old_inst.castTag(.deref).?), |
| 93 | .as => return analyzeInstAs(mod, scope, old_inst.castTag(.as).?), | 96 | .as => return analyzeInstAs(mod, scope, old_inst.castTag(.as).?), |
| 94 | .@"asm" => return analyzeInstAsm(mod, scope, old_inst.castTag(.@"asm").?), | 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,7 +106,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 103 | .intcast => return analyzeInstIntCast(mod, scope, old_inst.castTag(.intcast).?), | 106 | .intcast => return analyzeInstIntCast(mod, scope, old_inst.castTag(.intcast).?), |
| 104 | .bitcast => return analyzeInstBitCast(mod, scope, old_inst.castTag(.bitcast).?), | 107 | .bitcast => return analyzeInstBitCast(mod, scope, old_inst.castTag(.bitcast).?), |
| 105 | .floatcast => return analyzeInstFloatCast(mod, scope, old_inst.castTag(.floatcast).?), | 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 | .add => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.add).?), | 111 | .add => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.add).?), |
| 108 | .addwrap => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.addwrap).?), | 112 | .addwrap => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.addwrap).?), |
| 109 | .sub => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.sub).?), | 113 | .sub => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.sub).?), |
| ... | @@ -281,16 +285,16 @@ fn analyzeInstCoerceResultBlockPtr( | ... | @@ -281,16 +285,16 @@ fn analyzeInstCoerceResultBlockPtr( |
| 281 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{}); | 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 | const tracy = trace(@src()); | 289 | const tracy = trace(@src()); |
| 286 | defer tracy.end(); | 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 | const tracy = trace(@src()); | 295 | const tracy = trace(@src()); |
| 292 | defer tracy.end(); | 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 | fn analyzeInstCoerceResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 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,21 +322,12 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr |
| 318 | return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); | 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 | const tracy = trace(@src()); | 326 | const tracy = trace(@src()); |
| 323 | defer tracy.end(); | 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); | 329 | const operand = try resolveInst(mod, scope, inst.positionals.operand); |
| 335 | return mod.addUnOp(b, inst.base.src, ptr_type, .ref, operand); | 330 | return mod.analyzeRef(scope, inst.base.src, operand); |
| 336 | } | 331 | } |
| 337 | 332 | ||
| 338 | fn analyzeInstRetType(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | 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,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 | const tracy = trace(@src()); | 363 | const tracy = trace(@src()); |
| 369 | defer tracy.end(); | 364 | defer tracy.end(); |
| 370 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | 365 | |
| 371 | const elem_ty = operand.ty.elemType(); | 366 | const array_ptr = try resolveInst(mod, scope, inst.positionals.operand); |
| 372 | if (elem_ty.isIndexable()) { | 367 | const elem_ty = array_ptr.ty.elemType(); |
| 373 | return mod.constVoid(scope, operand.src); | 368 | if (!elem_ty.isIndexable()) { |
| 374 | } else { | 369 | const msg = msg: { |
| 375 | // TODO error notes | 370 | const msg = try mod.errMsg( |
| 376 | // error: type '{}' does not support indexing | 371 | scope, |
| 377 | // note: for loop operand must be an array, a slice or a tuple | 372 | inst.base.src, |
| 378 | return mod.fail(scope, operand.src, "for loop operand must be an array, a slice or a tuple", .{}); | 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 | fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 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,21 +836,19 @@ fn analyzeInstDeclRefStr(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr |
| 826 | return mod.analyzeDeclRefByName(scope, inst.base.src, decl_name); | 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 | const tracy = trace(@src()); | 840 | const tracy = trace(@src()); |
| 831 | defer tracy.end(); | 841 | defer tracy.end(); |
| 832 | return mod.analyzeDeclRef(scope, inst.base.src, inst.positionals.decl); | 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 | const tracy = trace(@src()); | 846 | const tracy = trace(@src()); |
| 837 | defer tracy.end(); | 847 | defer tracy.end(); |
| 838 | const decl_ref = try mod.analyzeDeclRef(scope, inst.base.src, inst.positionals.decl); | 848 | return mod.analyzeDeclVal(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); | ||
| 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 | const tracy = trace(@src()); | 852 | const tracy = trace(@src()); |
| 845 | defer tracy.end(); | 853 | defer tracy.end(); |
| 846 | 854 | ||
| ... | @@ -1093,7 +1101,7 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In | ... | @@ -1093,7 +1101,7 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In |
| 1093 | .val = Value.initPayload(&payload.base), | 1101 | .val = Value.initPayload(&payload.base), |
| 1094 | }); | 1102 | }); |
| 1095 | payload.data.decl = new_decl; | 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 | fn analyzeInstMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 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,108 +1301,46 @@ fn analyzeInstPtrToInt(mod: *Module, scope: *Scope, ptrtoint: *zir.Inst.UnOp) In |
| 1293 | return mod.addUnOp(b, ptrtoint.base.src, ty, .ptrtoint, ptr); | 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 | const tracy = trace(@src()); | 1305 | const tracy = trace(@src()); |
| 1298 | defer tracy.end(); | 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()) { | 1308 | const object = try resolveInst(mod, scope, inst.positionals.object); |
| 1303 | .Pointer => object_ptr.ty.elemType(), | 1309 | const field_name = inst.positionals.field_name; |
| 1304 | else => return mod.fail(scope, fieldptr.positionals.object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}), | 1310 | const object_ptr = try mod.analyzeRef(scope, inst.base.src, object); |
| 1305 | }; | 1311 | const result_ptr = try mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, inst.base.src); |
| 1306 | switch (elem_ty.zigTypeTag()) { | 1312 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); |
| 1307 | .Array => { | 1313 | } |
| 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 | } | ||
| 1385 | 1314 | ||
| 1386 | if (container_scope.file_scope == mod.root_scope) { | 1315 | fn fieldPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst { |
| 1387 | return mod.fail(scope, fieldptr.base.src, "root source file has no member called '{s}'", .{field_name}); | 1316 | const tracy = trace(@src()); |
| 1388 | } else { | 1317 | defer tracy.end(); |
| 1389 | return mod.fail(scope, fieldptr.base.src, "container '{}' has no member called '{s}'", .{ child_type, field_name }); | 1318 | |
| 1390 | } | 1319 | const object_ptr = try resolveInst(mod, scope, inst.positionals.object); |
| 1391 | }, | 1320 | const field_name = inst.positionals.field_name; |
| 1392 | else => return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{child_type}), | 1321 | return mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, inst.base.src); |
| 1393 | } | 1322 | } |
| 1394 | }, | 1323 | |
| 1395 | else => {}, | 1324 | fn fieldValNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerError!*Inst { |
| 1396 | } | 1325 | const tracy = trace(@src()); |
| 1397 | return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{elem_ty}); | 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 | fn analyzeInstIntCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 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,42 +1427,24 @@ fn analyzeInstFloatCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inne |
| 1481 | return mod.fail(scope, inst.base.src, "TODO implement analyze widen or shorten float", .{}); | 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 | const tracy = trace(@src()); | 1431 | const tracy = trace(@src()); |
| 1486 | defer tracy.end(); | 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()) { | 1434 | const array = try resolveInst(mod, scope, inst.positionals.array); |
| 1492 | .Pointer => array_ptr.ty.elemType(), | 1435 | const array_ptr = try mod.analyzeRef(scope, inst.base.src, array); |
| 1493 | else => return mod.fail(scope, inst.positionals.array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}), | 1436 | const elem_index = try resolveInst(mod, scope, inst.positionals.index); |
| 1494 | }; | 1437 | const result_ptr = try mod.elemPtr(scope, inst.base.src, array_ptr, elem_index); |
| 1495 | if (!elem_ty.isIndexable()) { | 1438 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); |
| 1496 | return mod.fail(scope, inst.base.src, "array access of non-array type '{}'", .{elem_ty}); | 1439 | } |
| 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(); | ||
| 1510 | 1440 | ||
| 1511 | return mod.constInst(scope, inst.base.src, .{ | 1441 | fn elemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst { |
| 1512 | .ty = try Type.Tag.single_const_pointer.create(scope.arena(), pointee_type), | 1442 | const tracy = trace(@src()); |
| 1513 | .val = elem_ptr, | 1443 | defer tracy.end(); |
| 1514 | }); | ||
| 1515 | } | ||
| 1516 | } | ||
| 1517 | } | ||
| 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 | fn analyzeInstSlice(mod: *Module, scope: *Scope, inst: *zir.Inst.Slice) InnerError!*Inst { | 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,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 | // Regular old hello world | 84 | // Regular old hello world |
| 85 | case.addCompareOutput( | 85 | case.addCompareOutput( |
| 86 | \\export fn _start() noreturn { | 86 | \\export fn _start() noreturn { |
test/stage2/arm.zig+1-1| ... | @@ -8,7 +8,7 @@ const linux_arm = std.zig.CrossTarget{ | ... | @@ -8,7 +8,7 @@ const linux_arm = std.zig.CrossTarget{ |
| 8 | 8 | ||
| 9 | pub fn addCases(ctx: *TestContext) !void { | 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 | // Regular old hello world | 12 | // Regular old hello world |
| 13 | case.addCompareOutput( | 13 | case.addCompareOutput( |
| 14 | \\export fn _start() noreturn { | 14 | \\export fn _start() noreturn { |
test/stage2/llvm.zig+1-1| ... | @@ -29,7 +29,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -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 | case.addCompareOutput( | 34 | case.addCompareOutput( |
| 35 | \\extern fn puts(s: [*:0]const u8) c_int; | 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,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 | // Regular old hello world | 235 | // Regular old hello world |
| 236 | case.addCompareOutput( | 236 | case.addCompareOutput( |
| 237 | \\export fn _start() noreturn { | 237 | \\export fn _start() noreturn { |