authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-19 13:56:48+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-19 16:12:29-07:00
log338a495648f07a2734e012034fd301a0e77f8202
tree020b47ea8f5e7a6f8906de9424cda1828d05ceca
parentb0846b6ecbb3e2557c5c95ddee04ecc055881d75

stage2: implement global variables


7 files changed, 266 insertions(+), 13 deletions(-)

src-self-hosted/Module.zig+210-8
......@@ -320,6 +320,12 @@ pub const Fn = struct {
320320 }
321321};
322322
323pub const Var = struct {
324 value: ?Value,
325 owner_decl: *Decl,
326 is_mutable: bool,
327};
328
323329pub const Scope = struct {
324330 tag: Tag,
325331
......@@ -1419,7 +1425,152 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
14191425 }
14201426 return type_changed;
14211427 },
1422 .VarDecl => @panic("TODO var decl"),
1428 .VarDecl => {
1429 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", ast_node);
1430
1431 decl.analysis = .in_progress;
1432
1433 const is_extern = blk: {
1434 const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse
1435 break :blk false;
1436 break :blk tree.token_ids[maybe_extern_token] == .Keyword_extern;
1437 };
1438 const is_mutable = tree.token_ids[var_decl.mut_token] == .Keyword_var;
1439
1440 // We need the memory for the Type to go into the arena for the Decl
1441 var decl_arena = std.heap.ArenaAllocator.init(self.gpa);
1442 errdefer decl_arena.deinit();
1443 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
1444
1445 var block_scope: Scope.Block = .{
1446 .parent = null,
1447 .func = null,
1448 .decl = decl,
1449 .instructions = .{},
1450 .arena = &decl_arena.allocator,
1451 };
1452 defer block_scope.instructions.deinit(self.gpa);
1453
1454 const explicit_type = blk: {
1455 const type_node = var_decl.getTrailer("type_node") orelse
1456 break :blk null;
1457
1458 var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1459 defer type_scope_arena.deinit();
1460 var type_scope: Scope.GenZIR = .{
1461 .decl = decl,
1462 .arena = &type_scope_arena.allocator,
1463 .parent = decl.scope,
1464 };
1465 defer type_scope.instructions.deinit(self.gpa);
1466
1467 const src = tree.token_locs[type_node.firstToken()].start;
1468 const type_type = try astgen.addZIRInstConst(self, &type_scope.base, src, .{
1469 .ty = Type.initTag(.type),
1470 .val = Value.initTag(.type_type),
1471 });
1472 const var_type = try astgen.expr(self, &type_scope.base, .{ .ty = type_type }, type_node);
1473 _ = try astgen.addZIRUnOp(self, &type_scope.base, src, .@"return", var_type);
1474
1475 break :blk try zir_sema.analyzeBodyValueAsType(self, &block_scope, .{
1476 .instructions = type_scope.instructions.items,
1477 });
1478 };
1479
1480 var var_type: Type = undefined;
1481 const value: ?Value = if (var_decl.getTrailer("init_node")) |init_node| blk: {
1482 var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1483 defer gen_scope_arena.deinit();
1484 var gen_scope: Scope.GenZIR = .{
1485 .decl = decl,
1486 .arena = &gen_scope_arena.allocator,
1487 .parent = decl.scope,
1488 };
1489 defer gen_scope.instructions.deinit(self.gpa);
1490 const src = tree.token_locs[init_node.firstToken()].start;
1491
1492 // TODO comptime scope here
1493 const init_inst = try astgen.expr(self, &gen_scope.base, .none, init_node);
1494 _ = try astgen.addZIRUnOp(self, &gen_scope.base, src, .@"return", init_inst);
1495
1496 var inner_block: Scope.Block = .{
1497 .parent = null,
1498 .func = null,
1499 .decl = decl,
1500 .instructions = .{},
1501 .arena = &gen_scope_arena.allocator,
1502 };
1503 defer inner_block.instructions.deinit(self.gpa);
1504 try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items });
1505
1506 for (inner_block.instructions.items) |inst| {
1507 if (inst.castTag(.ret)) |ret| {
1508 const coerced = if (explicit_type) |some|
1509 try self.coerce(&inner_block.base, some, ret.operand)
1510 else
1511 ret.operand;
1512 const val = try self.resolveConstValue(&inner_block.base, coerced);
1513
1514 var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena);
1515 break :blk try val.copy(block_scope.arena);
1516 } else {
1517 return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{});
1518 }
1519 }
1520 unreachable;
1521 } else if (!is_extern) {
1522 return self.failTok(&block_scope.base, var_decl.firstToken(), "variables must be initialized", .{});
1523 } else if (explicit_type) |some| blk: {
1524 var_type = some;
1525 break :blk null;
1526 } else {
1527 return self.failTok(&block_scope.base, var_decl.firstToken(), "unable to infer variable type", .{});
1528 };
1529
1530 if (is_mutable and !var_type.isValidVarType(is_extern)) {
1531 return self.failTok(&block_scope.base, var_decl.firstToken(), "variable of type '{}' must be const", .{var_type});
1532 }
1533
1534 var type_changed = true;
1535 if (decl.typedValueManaged()) |tvm| {
1536 type_changed = !tvm.typed_value.ty.eql(var_type);
1537
1538 tvm.deinit(self.gpa);
1539 }
1540
1541 const new_variable = try decl_arena.allocator.create(Var);
1542 const var_payload = try decl_arena.allocator.create(Value.Payload.Variable);
1543 new_variable.* = .{
1544 .value = value,
1545 .owner_decl = decl,
1546 .is_mutable = is_mutable,
1547 };
1548 var_payload.* = .{ .variable = new_variable };
1549
1550 decl_arena_state.* = decl_arena.state;
1551 decl.typed_value = .{
1552 .most_recent = .{
1553 .typed_value = .{
1554 .ty = var_type,
1555 .val = Value.initPayload(&var_payload.base),
1556 },
1557 .arena = decl_arena_state,
1558 },
1559 };
1560 decl.analysis = .complete;
1561 decl.generation = self.generation;
1562
1563 if (var_decl.getTrailer("extern_export_token")) |maybe_export_token| {
1564 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1565 const export_src = tree.token_locs[maybe_export_token].start;
1566 const name_loc = tree.token_locs[var_decl.name_token];
1567 const name = tree.tokenSliceLoc(name_loc);
1568 // The scope needs to have the decl in it.
1569 try self.analyzeExport(&block_scope.base, export_src, name, decl);
1570 }
1571 }
1572 return type_changed;
1573 },
14231574 .Comptime => @panic("TODO comptime decl"),
14241575 .Use => @panic("TODO usingnamespace decl"),
14251576 else => unreachable,
......@@ -1584,7 +1735,32 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
15841735 }
15851736 }
15861737 } else if (src_decl.castTag(.VarDecl)) |var_decl| {
1587 log.err("TODO: analyze var decl", .{});
1738 const name_loc = tree.token_locs[var_decl.name_token];
1739 const name = tree.tokenSliceLoc(name_loc);
1740 const name_hash = root_scope.fullyQualifiedNameHash(name);
1741 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1742 if (self.decl_table.get(name_hash)) |decl| {
1743 // Update the AST Node index of the decl, even if its contents are unchanged, it may
1744 // have been re-ordered.
1745 decl.src_index = decl_i;
1746 if (deleted_decls.remove(decl) == null) {
1747 decl.analysis = .sema_failure;
1748 const err_msg = try ErrorMsg.create(self.gpa, name_loc.start, "redefinition of '{}'", .{decl.name});
1749 errdefer err_msg.destroy(self.gpa);
1750 try self.failed_decls.putNoClobber(self.gpa, decl, err_msg);
1751 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
1752 try self.markOutdatedDecl(decl);
1753 decl.contents_hash = contents_hash;
1754 }
1755 } else {
1756 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
1757 root_scope.decls.appendAssumeCapacity(new_decl);
1758 if (var_decl.getTrailer("extern_export_token")) |maybe_export_token| {
1759 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1760 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
1761 }
1762 }
1763 }
15881764 } else if (src_decl.castTag(.Comptime)) |comptime_node| {
15891765 log.err("TODO: analyze comptime decl", .{});
15901766 } else if (src_decl.castTag(.ContainerField)) |container_field| {
......@@ -2217,20 +2393,46 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn
22172393 };
22182394
22192395 const decl_tv = try decl.typedValue();
2220 const ty_payload = try scope.arena().create(Type.Payload.Pointer);
2221 ty_payload.* = .{
2222 .base = .{ .tag = .single_const_pointer },
2223 .pointee_type = decl_tv.ty,
2224 };
2396 if (decl_tv.val.tag() == .variable) {
2397 return self.getVarRef(scope, src, decl_tv);
2398 }
2399 const ty = try self.singlePtrType(scope, src, false, decl_tv.ty);
22252400 const val_payload = try scope.arena().create(Value.Payload.DeclRef);
22262401 val_payload.* = .{ .decl = decl };
22272402
22282403 return self.constInst(scope, src, .{
2229 .ty = Type.initPayload(&ty_payload.base),
2404 .ty = ty,
22302405 .val = Value.initPayload(&val_payload.base),
22312406 });
22322407}
22332408
2409fn getVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst {
2410 const variable = tv.val.cast(Value.Payload.Variable).?.variable;
2411
2412 const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty);
2413 if (!variable.is_mutable and variable.value != null) {
2414 const val_payload = try scope.arena().create(Value.Payload.RefVal);
2415 val_payload.* = .{ .val = variable.value.? };
2416 return self.constInst(scope, src, .{
2417 .ty = ty,
2418 .val = Value.initPayload(&val_payload.base),
2419 });
2420 }
2421
2422 const b = try self.requireRuntimeBlock(scope, src);
2423 const inst = try b.arena.create(Inst.VarPtr);
2424 inst.* = .{
2425 .base = .{
2426 .tag = .varptr,
2427 .ty = ty,
2428 .src = src,
2429 },
2430 .variable = variable,
2431 };
2432 try b.instructions.append(self.gpa, &inst.base);
2433 return &inst.base;
2434}
2435
22342436pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst {
22352437 const elem_ty = switch (ptr.ty.zigTypeTag()) {
22362438 .Pointer => ptr.ty.elemType(),
src-self-hosted/codegen.zig+11
......@@ -684,6 +684,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
684684 .unreach => return MCValue{ .unreach = {} },
685685 .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),
686686 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
687 .varptr => return self.genVarPtr(inst.castTag(.varptr).?),
687688 }
688689 }
689690
......@@ -858,6 +859,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
858859 }
859860 }
860861
862 fn genVarPtr(self: *Self, inst: *ir.Inst.VarPtr) !MCValue {
863 // No side effects, so if it's unreferenced, do nothing.
864 if (inst.base.isUnused())
865 return MCValue.dead;
866
867 switch (arch) {
868 else => return self.fail(inst.base.src, "TODO implement varptr for {}", .{self.target.cpu.arch}),
869 }
870 }
871
861872 fn reuseOperand(inst: *ir.Inst, op_index: ir.Inst.DeathsBitIndex, mcv: MCValue) bool {
862873 if (!inst.operandDies(op_index) or !mcv.isMutable())
863874 return false;
src-self-hosted/ir.zig+16
......@@ -81,6 +81,7 @@ pub const Inst = struct {
8181 ref,
8282 ret,
8383 retvoid,
84 varptr,
8485 /// Write a value to a pointer. LHS is pointer, RHS is value.
8586 store,
8687 sub,
......@@ -135,6 +136,7 @@ pub const Inst = struct {
135136 .condbr => CondBr,
136137 .constant => Constant,
137138 .loop => Loop,
139 .varptr => VarPtr,
138140 };
139141 }
140142
......@@ -434,6 +436,20 @@ pub const Inst = struct {
434436 return null;
435437 }
436438 };
439
440 pub const VarPtr = struct {
441 pub const base_tag = Tag.varptr;
442
443 base: Inst,
444 variable: *Module.Var,
445
446 pub fn operandCount(self: *const VarPtr) usize {
447 return 0;
448 }
449 pub fn getOperand(self: *const VarPtr, index: usize) ?*Inst {
450 return null;
451 }
452 };
437453};
438454
439455pub const Body = struct {
src-self-hosted/type.zig+3-3
......@@ -1074,7 +1074,7 @@ pub const Type = extern union {
10741074 }
10751075
10761076 /// Returns if type can be used for a runtime variable
1077 pub fn isValidVarType(self: Type) bool {
1077 pub fn isValidVarType(self: Type, is_extern: bool) bool {
10781078 var ty = self;
10791079 while (true) switch (ty.zigTypeTag()) {
10801080 .Bool,
......@@ -1087,6 +1087,7 @@ pub const Type = extern union {
10871087 .Vector,
10881088 => return true,
10891089
1090 .Opaque => return is_extern,
10901091 .BoundFn,
10911092 .ComptimeFloat,
10921093 .ComptimeInt,
......@@ -1096,12 +1097,11 @@ pub const Type = extern union {
10961097 .Void,
10971098 .Undefined,
10981099 .Null,
1099 .Opaque,
11001100 => return false,
11011101
11021102 .Optional => {
11031103 var buf: Payload.Pointer = undefined;
1104 return ty.optionalChild(&buf).isValidVarType();
1104 return ty.optionalChild(&buf).isValidVarType(is_extern);
11051105 },
11061106 .Pointer, .Array => ty = ty.elemType(),
11071107
src-self-hosted/value.zig+19
......@@ -79,6 +79,7 @@ pub const Value = extern union {
7979 int_big_positive,
8080 int_big_negative,
8181 function,
82 variable,
8283 ref_val,
8384 decl_ref,
8485 elem_ptr,
......@@ -196,6 +197,7 @@ pub const Value = extern union {
196197 @panic("TODO implement copying of big ints");
197198 },
198199 .function => return self.copyPayloadShallow(allocator, Payload.Function),
200 .variable => return self.copyPayloadShallow(allocator, Payload.Variable),
199201 .ref_val => {
200202 const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
201203 const new_payload = try allocator.create(Payload.RefVal);
......@@ -310,6 +312,7 @@ pub const Value = extern union {
310312 .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}),
311313 .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}),
312314 .function => return out_stream.writeAll("(function)"),
315 .variable => return out_stream.writeAll("(variable)"),
313316 .ref_val => {
314317 const ref_val = val.cast(Payload.RefVal).?;
315318 try out_stream.writeAll("&const ");
......@@ -410,6 +413,7 @@ pub const Value = extern union {
410413 .int_big_positive,
411414 .int_big_negative,
412415 .function,
416 .variable,
413417 .ref_val,
414418 .decl_ref,
415419 .elem_ptr,
......@@ -471,6 +475,7 @@ pub const Value = extern union {
471475 .enum_literal_type,
472476 .null_value,
473477 .function,
478 .variable,
474479 .ref_val,
475480 .decl_ref,
476481 .elem_ptr,
......@@ -548,6 +553,7 @@ pub const Value = extern union {
548553 .enum_literal_type,
549554 .null_value,
550555 .function,
556 .variable,
551557 .ref_val,
552558 .decl_ref,
553559 .elem_ptr,
......@@ -625,6 +631,7 @@ pub const Value = extern union {
625631 .enum_literal_type,
626632 .null_value,
627633 .function,
634 .variable,
628635 .ref_val,
629636 .decl_ref,
630637 .elem_ptr,
......@@ -728,6 +735,7 @@ pub const Value = extern union {
728735 .enum_literal_type,
729736 .null_value,
730737 .function,
738 .variable,
731739 .ref_val,
732740 .decl_ref,
733741 .elem_ptr,
......@@ -810,6 +818,7 @@ pub const Value = extern union {
810818 .enum_literal_type,
811819 .null_value,
812820 .function,
821 .variable,
813822 .ref_val,
814823 .decl_ref,
815824 .elem_ptr,
......@@ -974,6 +983,7 @@ pub const Value = extern union {
974983 .bool_false,
975984 .null_value,
976985 .function,
986 .variable,
977987 .ref_val,
978988 .decl_ref,
979989 .elem_ptr,
......@@ -1046,6 +1056,7 @@ pub const Value = extern union {
10461056 .enum_literal_type,
10471057 .null_value,
10481058 .function,
1059 .variable,
10491060 .ref_val,
10501061 .decl_ref,
10511062 .elem_ptr,
......@@ -1182,6 +1193,7 @@ pub const Value = extern union {
11821193 .bool_false,
11831194 .null_value,
11841195 .function,
1196 .variable,
11851197 .int_u64,
11861198 .int_i64,
11871199 .int_big_positive,
......@@ -1260,6 +1272,7 @@ pub const Value = extern union {
12601272 .bool_false,
12611273 .null_value,
12621274 .function,
1275 .variable,
12631276 .int_u64,
12641277 .int_i64,
12651278 .int_big_positive,
......@@ -1355,6 +1368,7 @@ pub const Value = extern union {
13551368 .bool_true,
13561369 .bool_false,
13571370 .function,
1371 .variable,
13581372 .int_u64,
13591373 .int_i64,
13601374 .int_big_positive,
......@@ -1429,6 +1443,11 @@ pub const Value = extern union {
14291443 func: *Module.Fn,
14301444 };
14311445
1446 pub const Variable = struct {
1447 base: Payload = Payload{ .tag = .variable },
1448 variable: *Module.Var,
1449 };
1450
14321451 pub const ArraySentinel0_u8_Type = struct {
14331452 base: Payload = Payload{ .tag = .array_sentinel_0_u8_type },
14341453 len: u64,
src-self-hosted/zir.zig+5
......@@ -1752,6 +1752,9 @@ const EmitZIR = struct {
17521752 const decl_ref = try self.emitDeclRef(inst.src, declref.decl);
17531753 try new_body.instructions.append(decl_ref);
17541754 break :blk decl_ref;
1755 } else if (const_inst.val.cast(Value.Payload.Variable)) |var_pl| blk: {
1756 const owner_decl = var_pl.variable.owner_decl;
1757 break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name));
17551758 } else blk: {
17561759 break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst;
17571760 };
......@@ -2311,6 +2314,8 @@ const EmitZIR = struct {
23112314 };
23122315 break :blk &new_inst.base;
23132316 },
2317
2318 .varptr => @panic("TODO"),
23142319 };
23152320 try self.metadata.put(new_inst, .{ .deaths = inst.deaths });
23162321 try instructions.append(new_inst);
src-self-hosted/zir_sema.zig+2-2
......@@ -366,7 +366,7 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.
366366fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
367367 const var_type = try resolveType(mod, scope, inst.positionals.operand);
368368 // TODO this should happen only for var allocs
369 if (!var_type.isValidVarType()) {
369 if (!var_type.isValidVarType(false)) {
370370 return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type});
371371 }
372372 const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type);
......@@ -779,7 +779,7 @@ fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inne
779779 for (fntype.positionals.param_types) |param_type, i| {
780780 const resolved = try resolveType(mod, scope, param_type);
781781 // TODO skip for comptime params
782 if (!resolved.isValidVarType()) {
782 if (!resolved.isValidVarType(false)) {
783783 return mod.fail(scope, param_type.src, "parameter of type '{}' must be declared comptime", .{resolved});
784784 }
785785 param_types[i] = resolved;