authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-19 00:38:53-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-19 00:38:53-07:00
log30a824cb9e148adb0799a0a81721160c0d474b50
treeafdfb0a3e19fb956c66ade7b190b7ca4566ba7f7
parent7e56028bc7c00b884c92e2948728cbc47e5a8a09

astgen: eliminate rlWrapPtr and all its callsites

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}
23592359
2360pub 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
2360pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {2365pub 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}
24102415
2416pub 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
2411pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst {2430pub 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
3566pub 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
3672pub 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}
11091109
1110fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst {1110fn 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 }
11201120
1121 // analyzing the error set results in a decl ref, so we might need to dereference it1121 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}
11251123
1126fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {1124fn 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}
13011299
1302pub fn identifierStringInst(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {1300pub 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;
13051303 // 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);
13071305 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}
13101316
1311fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {1317fn 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();
13141328
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 };
13171334
1318 // TODO remove all callsites to rlWrapPtr1335 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}
13211346
1322fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ArrayAccess) InnerError!*zir.Inst {1347fn 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 };
13251355
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, .{
13281358 .array = try expr(mod, scope, .ref, node.lhs),
1329 // TODO remove all callsites to rlWrapPtr1359 .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}
13321367
1333fn sliceExpr(mod: *Module, scope: *Scope, node: *ast.Node.Slice) InnerError!*zir.Inst {1368fn 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 }, .{});
18281859
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(
18451876
1846 // check condition i < array_expr.len1877 // 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);
18501880
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 rlWrapPtr2361 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}
31213154
3155pub 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
3122pub fn addZIRInstSpecial(3177pub 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 sentinel48 /// 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 at147 /// 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 pointer162 /// 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,
395408
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 };
825843
826 pub const FieldPtr = struct {844 pub const Field = struct {
827 pub const base_tag = Tag.fieldptr;
828 base: Inst,845 base: Inst,
829846
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 };
10021029
1003 pub const ElemPtr = struct {1030 pub const Elem = struct {
1004 pub const base_tag = Tag.elemptr;
1005 base: Inst,1031 base: Inst,
10061032
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}
283287
284fn analyzeInstBitCastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {288fn 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}
289293
290fn analyzeInstBitCastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {294fn 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}
295299
296fn analyzeInstCoerceResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {300fn 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}
320324
321fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {325fn 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 }
333328
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}
337332
338fn analyzeInstRetType(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {333fn 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}
366361
367fn analyzeInstEnsureIndexable(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {362fn 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 notes370 const msg = try mod.errMsg(
376 // error: type '{}' does not support indexing371 scope,
377 // note: for loop operand must be an array, a slice or a tuple372 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}
381391
382fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {392fn 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}
828838
829fn analyzeInstDeclRef(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst {839fn 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}
834844
835fn analyzeInstDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Inst {845fn 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}
842850
843fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {851fn 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();
846854
...@@ -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}
10981106
1099fn analyzeInstMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {1107fn 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}
12951303
1296fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr) InnerError!*Inst {1304fn 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);
13011307
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 }
13851314
1386 if (container_scope.file_scope == mod.root_scope) {1315fn 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 => {},1324fn 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
1336fn 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}
13991345
1400fn analyzeInstIntCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {1346fn 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}
14831429
1484fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) InnerError!*Inst {1430fn 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);
14901433
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();
15101440
1511 return mod.constInst(scope, inst.base.src, .{1441fn 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 }
15181444
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}
15211449
1522fn analyzeInstSlice(mod: *Module, scope: *Scope, inst: *zir.Inst.Slice) InnerError!*Inst {1450fn 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 }
8181
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 world84 // 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{
88
9pub fn addCases(ctx: *TestContext) !void {9pub 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 world12 // 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 }
3030
31 {31 {
32 var case = ctx.exeUsingLlvmBackend("hello world", linux_x64);32 var case = ctx.exeUsingLlvmBackend("llvm hello world", linux_x64);
3333
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 }
232232
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 world235 // Regular old hello world
236 case.addCompareOutput(236 case.addCompareOutput(
237 \\export fn _start() noreturn {237 \\export fn _start() noreturn {