| author | |
| committer | |
| log | a30950706f858e052376fb2d526895970f59d0ca |
| tree | 31f0da7dad51bcf707cba8555d7aa33f0ab0a1ba |
| parent | b0846b6ecbb3e2557c5c95ddee04ecc055881d75 |
| parent | 9ec9c0f5e57820f4baa04b9674a6a4a88235b863 |
closes #60939 files changed, 415 insertions(+), 23 deletions(-)
src-self-hosted/Module.zig+240-8| ... | @@ -170,6 +170,9 @@ pub const Decl = struct { | ... | @@ -170,6 +170,9 @@ pub const Decl = struct { |
| 170 | /// This flag is set when this Decl is added to a check_for_deletion set, and cleared | 170 | /// This flag is set when this Decl is added to a check_for_deletion set, and cleared |
| 171 | /// when removed. | 171 | /// when removed. |
| 172 | deletion_flag: bool, | 172 | deletion_flag: bool, |
| 173 | /// Whether the corresponding AST decl has a `pub` keyword. | ||
| 174 | is_pub: bool, | ||
| 175 | |||
| 173 | /// An integer that can be checked against the corresponding incrementing | 176 | /// An integer that can be checked against the corresponding incrementing |
| 174 | /// generation field of Module. This is used to determine whether `complete` status | 177 | /// generation field of Module. This is used to determine whether `complete` status |
| 175 | /// represents pre- or post- re-analysis. | 178 | /// represents pre- or post- re-analysis. |
| ... | @@ -320,6 +323,16 @@ pub const Fn = struct { | ... | @@ -320,6 +323,16 @@ pub const Fn = struct { |
| 320 | } | 323 | } |
| 321 | }; | 324 | }; |
| 322 | 325 | ||
| 326 | pub const Var = struct { | ||
| 327 | init: Value, | ||
| 328 | owner_decl: *Decl, | ||
| 329 | |||
| 330 | has_init: bool, | ||
| 331 | is_extern: bool, | ||
| 332 | is_mutable: bool, | ||
| 333 | is_threadlocal: bool, | ||
| 334 | }; | ||
| 335 | |||
| 323 | pub const Scope = struct { | 336 | pub const Scope = struct { |
| 324 | tag: Tag, | 337 | tag: Tag, |
| 325 | 338 | ||
| ... | @@ -1235,6 +1248,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1235,6 +1248,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1235 | }; | 1248 | }; |
| 1236 | defer fn_type_scope.instructions.deinit(self.gpa); | 1249 | defer fn_type_scope.instructions.deinit(self.gpa); |
| 1237 | 1250 | ||
| 1251 | decl.is_pub = fn_proto.getTrailer("visib_token") != null; | ||
| 1238 | const body_node = fn_proto.getTrailer("body_node") orelse | 1252 | const body_node = fn_proto.getTrailer("body_node") orelse |
| 1239 | return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{}); | 1253 | return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{}); |
| 1240 | 1254 | ||
| ... | @@ -1419,7 +1433,173 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1419,7 +1433,173 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1419 | } | 1433 | } |
| 1420 | return type_changed; | 1434 | return type_changed; |
| 1421 | }, | 1435 | }, |
| 1422 | .VarDecl => @panic("TODO var decl"), | 1436 | .VarDecl => { |
| 1437 | const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", ast_node); | ||
| 1438 | |||
| 1439 | decl.analysis = .in_progress; | ||
| 1440 | |||
| 1441 | // We need the memory for the Type to go into the arena for the Decl | ||
| 1442 | var decl_arena = std.heap.ArenaAllocator.init(self.gpa); | ||
| 1443 | errdefer decl_arena.deinit(); | ||
| 1444 | const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); | ||
| 1445 | |||
| 1446 | var block_scope: Scope.Block = .{ | ||
| 1447 | .parent = null, | ||
| 1448 | .func = null, | ||
| 1449 | .decl = decl, | ||
| 1450 | .instructions = .{}, | ||
| 1451 | .arena = &decl_arena.allocator, | ||
| 1452 | }; | ||
| 1453 | defer block_scope.instructions.deinit(self.gpa); | ||
| 1454 | |||
| 1455 | decl.is_pub = var_decl.getTrailer("visib_token") != null; | ||
| 1456 | const is_extern = blk: { | ||
| 1457 | const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse | ||
| 1458 | break :blk false; | ||
| 1459 | break :blk tree.token_ids[maybe_extern_token] == .Keyword_extern; | ||
| 1460 | }; | ||
| 1461 | if (var_decl.getTrailer("lib_name")) |lib_name| { | ||
| 1462 | assert(is_extern); | ||
| 1463 | return self.failNode(&block_scope.base, lib_name, "TODO implement function library name", .{}); | ||
| 1464 | } | ||
| 1465 | const is_mutable = tree.token_ids[var_decl.mut_token] == .Keyword_var; | ||
| 1466 | const is_threadlocal = if (var_decl.getTrailer("thread_local_token")) |some| blk: { | ||
| 1467 | if (!is_mutable) { | ||
| 1468 | return self.failTok(&block_scope.base, some, "threadlocal variable cannot be constant", .{}); | ||
| 1469 | } | ||
| 1470 | break :blk true; | ||
| 1471 | } else false; | ||
| 1472 | assert(var_decl.getTrailer("comptime_token") == null); | ||
| 1473 | if (var_decl.getTrailer("align_node")) |align_expr| { | ||
| 1474 | return self.failNode(&block_scope.base, align_expr, "TODO implement function align expression", .{}); | ||
| 1475 | } | ||
| 1476 | if (var_decl.getTrailer("section_node")) |sect_expr| { | ||
| 1477 | return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{}); | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | const explicit_type = blk: { | ||
| 1481 | const type_node = var_decl.getTrailer("type_node") orelse | ||
| 1482 | break :blk null; | ||
| 1483 | |||
| 1484 | var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa); | ||
| 1485 | defer type_scope_arena.deinit(); | ||
| 1486 | var type_scope: Scope.GenZIR = .{ | ||
| 1487 | .decl = decl, | ||
| 1488 | .arena = &type_scope_arena.allocator, | ||
| 1489 | .parent = decl.scope, | ||
| 1490 | }; | ||
| 1491 | defer type_scope.instructions.deinit(self.gpa); | ||
| 1492 | |||
| 1493 | const src = tree.token_locs[type_node.firstToken()].start; | ||
| 1494 | const type_type = try astgen.addZIRInstConst(self, &type_scope.base, src, .{ | ||
| 1495 | .ty = Type.initTag(.type), | ||
| 1496 | .val = Value.initTag(.type_type), | ||
| 1497 | }); | ||
| 1498 | const var_type = try astgen.expr(self, &type_scope.base, .{ .ty = type_type }, type_node); | ||
| 1499 | _ = try astgen.addZIRUnOp(self, &type_scope.base, src, .@"return", var_type); | ||
| 1500 | |||
| 1501 | break :blk try zir_sema.analyzeBodyValueAsType(self, &block_scope, .{ | ||
| 1502 | .instructions = type_scope.instructions.items, | ||
| 1503 | }); | ||
| 1504 | }; | ||
| 1505 | |||
| 1506 | var var_type: Type = undefined; | ||
| 1507 | const value: ?Value = if (var_decl.getTrailer("init_node")) |init_node| blk: { | ||
| 1508 | var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa); | ||
| 1509 | defer gen_scope_arena.deinit(); | ||
| 1510 | var gen_scope: Scope.GenZIR = .{ | ||
| 1511 | .decl = decl, | ||
| 1512 | .arena = &gen_scope_arena.allocator, | ||
| 1513 | .parent = decl.scope, | ||
| 1514 | }; | ||
| 1515 | defer gen_scope.instructions.deinit(self.gpa); | ||
| 1516 | const src = tree.token_locs[init_node.firstToken()].start; | ||
| 1517 | |||
| 1518 | // TODO comptime scope here | ||
| 1519 | const init_inst = try astgen.expr(self, &gen_scope.base, .none, init_node); | ||
| 1520 | _ = try astgen.addZIRUnOp(self, &gen_scope.base, src, .@"return", init_inst); | ||
| 1521 | |||
| 1522 | var inner_block: Scope.Block = .{ | ||
| 1523 | .parent = null, | ||
| 1524 | .func = null, | ||
| 1525 | .decl = decl, | ||
| 1526 | .instructions = .{}, | ||
| 1527 | .arena = &gen_scope_arena.allocator, | ||
| 1528 | }; | ||
| 1529 | defer inner_block.instructions.deinit(self.gpa); | ||
| 1530 | try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items }); | ||
| 1531 | |||
| 1532 | for (inner_block.instructions.items) |inst| { | ||
| 1533 | if (inst.castTag(.ret)) |ret| { | ||
| 1534 | const coerced = if (explicit_type) |some| | ||
| 1535 | try self.coerce(&inner_block.base, some, ret.operand) | ||
| 1536 | else | ||
| 1537 | ret.operand; | ||
| 1538 | const val = try self.resolveConstValue(&inner_block.base, coerced); | ||
| 1539 | |||
| 1540 | var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena); | ||
| 1541 | break :blk try val.copy(block_scope.arena); | ||
| 1542 | } else { | ||
| 1543 | return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); | ||
| 1544 | } | ||
| 1545 | } | ||
| 1546 | unreachable; | ||
| 1547 | } else if (!is_extern) { | ||
| 1548 | return self.failTok(&block_scope.base, var_decl.firstToken(), "variables must be initialized", .{}); | ||
| 1549 | } else if (explicit_type) |some| blk: { | ||
| 1550 | var_type = some; | ||
| 1551 | break :blk null; | ||
| 1552 | } else { | ||
| 1553 | return self.failTok(&block_scope.base, var_decl.firstToken(), "unable to infer variable type", .{}); | ||
| 1554 | }; | ||
| 1555 | |||
| 1556 | if (is_mutable and !var_type.isValidVarType(is_extern)) { | ||
| 1557 | return self.failTok(&block_scope.base, var_decl.firstToken(), "variable of type '{}' must be const", .{var_type}); | ||
| 1558 | } | ||
| 1559 | |||
| 1560 | var type_changed = true; | ||
| 1561 | if (decl.typedValueManaged()) |tvm| { | ||
| 1562 | type_changed = !tvm.typed_value.ty.eql(var_type); | ||
| 1563 | |||
| 1564 | tvm.deinit(self.gpa); | ||
| 1565 | } | ||
| 1566 | |||
| 1567 | const new_variable = try decl_arena.allocator.create(Var); | ||
| 1568 | const var_payload = try decl_arena.allocator.create(Value.Payload.Variable); | ||
| 1569 | new_variable.* = .{ | ||
| 1570 | .owner_decl = decl, | ||
| 1571 | .init = value orelse undefined, | ||
| 1572 | .has_init = value != null, | ||
| 1573 | .is_extern = is_extern, | ||
| 1574 | .is_mutable = is_mutable, | ||
| 1575 | .is_threadlocal = is_threadlocal, | ||
| 1576 | }; | ||
| 1577 | var_payload.* = .{ .variable = new_variable }; | ||
| 1578 | |||
| 1579 | decl_arena_state.* = decl_arena.state; | ||
| 1580 | decl.typed_value = .{ | ||
| 1581 | .most_recent = .{ | ||
| 1582 | .typed_value = .{ | ||
| 1583 | .ty = var_type, | ||
| 1584 | .val = Value.initPayload(&var_payload.base), | ||
| 1585 | }, | ||
| 1586 | .arena = decl_arena_state, | ||
| 1587 | }, | ||
| 1588 | }; | ||
| 1589 | decl.analysis = .complete; | ||
| 1590 | decl.generation = self.generation; | ||
| 1591 | |||
| 1592 | if (var_decl.getTrailer("extern_export_token")) |maybe_export_token| { | ||
| 1593 | if (tree.token_ids[maybe_export_token] == .Keyword_export) { | ||
| 1594 | const export_src = tree.token_locs[maybe_export_token].start; | ||
| 1595 | const name_loc = tree.token_locs[var_decl.name_token]; | ||
| 1596 | const name = tree.tokenSliceLoc(name_loc); | ||
| 1597 | // The scope needs to have the decl in it. | ||
| 1598 | try self.analyzeExport(&block_scope.base, export_src, name, decl); | ||
| 1599 | } | ||
| 1600 | } | ||
| 1601 | return type_changed; | ||
| 1602 | }, | ||
| 1423 | .Comptime => @panic("TODO comptime decl"), | 1603 | .Comptime => @panic("TODO comptime decl"), |
| 1424 | .Use => @panic("TODO usingnamespace decl"), | 1604 | .Use => @panic("TODO usingnamespace decl"), |
| 1425 | else => unreachable, | 1605 | else => unreachable, |
| ... | @@ -1584,7 +1764,32 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { | ... | @@ -1584,7 +1764,32 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { |
| 1584 | } | 1764 | } |
| 1585 | } | 1765 | } |
| 1586 | } else if (src_decl.castTag(.VarDecl)) |var_decl| { | 1766 | } else if (src_decl.castTag(.VarDecl)) |var_decl| { |
| 1587 | log.err("TODO: analyze var decl", .{}); | 1767 | const name_loc = tree.token_locs[var_decl.name_token]; |
| 1768 | const name = tree.tokenSliceLoc(name_loc); | ||
| 1769 | const name_hash = root_scope.fullyQualifiedNameHash(name); | ||
| 1770 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl)); | ||
| 1771 | if (self.decl_table.get(name_hash)) |decl| { | ||
| 1772 | // Update the AST Node index of the decl, even if its contents are unchanged, it may | ||
| 1773 | // have been re-ordered. | ||
| 1774 | decl.src_index = decl_i; | ||
| 1775 | if (deleted_decls.remove(decl) == null) { | ||
| 1776 | decl.analysis = .sema_failure; | ||
| 1777 | const err_msg = try ErrorMsg.create(self.gpa, name_loc.start, "redefinition of '{}'", .{decl.name}); | ||
| 1778 | errdefer err_msg.destroy(self.gpa); | ||
| 1779 | try self.failed_decls.putNoClobber(self.gpa, decl, err_msg); | ||
| 1780 | } else if (!srcHashEql(decl.contents_hash, contents_hash)) { | ||
| 1781 | try self.markOutdatedDecl(decl); | ||
| 1782 | decl.contents_hash = contents_hash; | ||
| 1783 | } | ||
| 1784 | } else { | ||
| 1785 | const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash); | ||
| 1786 | root_scope.decls.appendAssumeCapacity(new_decl); | ||
| 1787 | if (var_decl.getTrailer("extern_export_token")) |maybe_export_token| { | ||
| 1788 | if (tree.token_ids[maybe_export_token] == .Keyword_export) { | ||
| 1789 | self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); | ||
| 1790 | } | ||
| 1791 | } | ||
| 1792 | } | ||
| 1588 | } else if (src_decl.castTag(.Comptime)) |comptime_node| { | 1793 | } else if (src_decl.castTag(.Comptime)) |comptime_node| { |
| 1589 | log.err("TODO: analyze comptime decl", .{}); | 1794 | log.err("TODO: analyze comptime decl", .{}); |
| 1590 | } else if (src_decl.castTag(.ContainerField)) |container_field| { | 1795 | } else if (src_decl.castTag(.ContainerField)) |container_field| { |
| ... | @@ -1798,6 +2003,7 @@ fn allocateNewDecl( | ... | @@ -1798,6 +2003,7 @@ fn allocateNewDecl( |
| 1798 | .wasm => .{ .wasm = null }, | 2003 | .wasm => .{ .wasm = null }, |
| 1799 | }, | 2004 | }, |
| 1800 | .generation = 0, | 2005 | .generation = 0, |
| 2006 | .is_pub = false, | ||
| 1801 | }; | 2007 | }; |
| 1802 | return new_decl; | 2008 | return new_decl; |
| 1803 | } | 2009 | } |
| ... | @@ -2217,20 +2423,46 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn | ... | @@ -2217,20 +2423,46 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn |
| 2217 | }; | 2423 | }; |
| 2218 | 2424 | ||
| 2219 | const decl_tv = try decl.typedValue(); | 2425 | const decl_tv = try decl.typedValue(); |
| 2220 | const ty_payload = try scope.arena().create(Type.Payload.Pointer); | 2426 | if (decl_tv.val.tag() == .variable) { |
| 2221 | ty_payload.* = .{ | 2427 | return self.analyzeVarRef(scope, src, decl_tv); |
| 2222 | .base = .{ .tag = .single_const_pointer }, | 2428 | } |
| 2223 | .pointee_type = decl_tv.ty, | 2429 | const ty = try self.singlePtrType(scope, src, false, decl_tv.ty); |
| 2224 | }; | ||
| 2225 | const val_payload = try scope.arena().create(Value.Payload.DeclRef); | 2430 | const val_payload = try scope.arena().create(Value.Payload.DeclRef); |
| 2226 | val_payload.* = .{ .decl = decl }; | 2431 | val_payload.* = .{ .decl = decl }; |
| 2227 | 2432 | ||
| 2228 | return self.constInst(scope, src, .{ | 2433 | return self.constInst(scope, src, .{ |
| 2229 | .ty = Type.initPayload(&ty_payload.base), | 2434 | .ty = ty, |
| 2230 | .val = Value.initPayload(&val_payload.base), | 2435 | .val = Value.initPayload(&val_payload.base), |
| 2231 | }); | 2436 | }); |
| 2232 | } | 2437 | } |
| 2233 | 2438 | ||
| 2439 | fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { | ||
| 2440 | const variable = tv.val.cast(Value.Payload.Variable).?.variable; | ||
| 2441 | |||
| 2442 | const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty); | ||
| 2443 | if (!variable.is_mutable and !variable.is_extern and variable.has_init) { | ||
| 2444 | const val_payload = try scope.arena().create(Value.Payload.RefVal); | ||
| 2445 | val_payload.* = .{ .val = variable.init }; | ||
| 2446 | return self.constInst(scope, src, .{ | ||
| 2447 | .ty = ty, | ||
| 2448 | .val = Value.initPayload(&val_payload.base), | ||
| 2449 | }); | ||
| 2450 | } | ||
| 2451 | |||
| 2452 | const b = try self.requireRuntimeBlock(scope, src); | ||
| 2453 | const inst = try b.arena.create(Inst.VarPtr); | ||
| 2454 | inst.* = .{ | ||
| 2455 | .base = .{ | ||
| 2456 | .tag = .varptr, | ||
| 2457 | .ty = ty, | ||
| 2458 | .src = src, | ||
| 2459 | }, | ||
| 2460 | .variable = variable, | ||
| 2461 | }; | ||
| 2462 | try b.instructions.append(self.gpa, &inst.base); | ||
| 2463 | return &inst.base; | ||
| 2464 | } | ||
| 2465 | |||
| 2234 | pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst { | 2466 | pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst { |
| 2235 | const elem_ty = switch (ptr.ty.zigTypeTag()) { | 2467 | const elem_ty = switch (ptr.ty.zigTypeTag()) { |
| 2236 | .Pointer => ptr.ty.elemType(), | 2468 | .Pointer => ptr.ty.elemType(), |
src-self-hosted/astgen.zig+8-6| ... | @@ -1223,9 +1223,10 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo | ... | @@ -1223,9 +1223,10 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo |
| 1223 | } | 1223 | } |
| 1224 | 1224 | ||
| 1225 | if (mod.lookupDeclName(scope, ident_name)) |decl| { | 1225 | if (mod.lookupDeclName(scope, ident_name)) |decl| { |
| 1226 | // TODO handle lvalues | ||
| 1227 | const result = try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}); | 1226 | const result = try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}); |
| 1228 | return rlWrap(mod, scope, rl, result); | 1227 | if (rl == .lvalue or rl == .ref) |
| 1228 | return result; | ||
| 1229 | return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, result)); | ||
| 1229 | } | 1230 | } |
| 1230 | 1231 | ||
| 1231 | return mod.failNode(scope, &ident.base, "use of undeclared identifier '{}'", .{ident_name}); | 1232 | return mod.failNode(scope, &ident.base, "use of undeclared identifier '{}'", .{ident_name}); |
| ... | @@ -1258,7 +1259,8 @@ fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStr | ... | @@ -1258,7 +1259,8 @@ fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStr |
| 1258 | // line lengths and new lines | 1259 | // line lengths and new lines |
| 1259 | var len = lines.len - 1; | 1260 | var len = lines.len - 1; |
| 1260 | for (lines) |line| { | 1261 | for (lines) |line| { |
| 1261 | len += tree.tokenSlice(line).len - 2; | 1262 | // 2 for the '//' + 1 for '\n' |
| 1263 | len += tree.tokenSlice(line).len - 3; | ||
| 1262 | } | 1264 | } |
| 1263 | 1265 | ||
| 1264 | const bytes = try scope.arena().alloc(u8, len); | 1266 | const bytes = try scope.arena().alloc(u8, len); |
| ... | @@ -1268,9 +1270,9 @@ fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStr | ... | @@ -1268,9 +1270,9 @@ fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStr |
| 1268 | bytes[i] = '\n'; | 1270 | bytes[i] = '\n'; |
| 1269 | i += 1; | 1271 | i += 1; |
| 1270 | } | 1272 | } |
| 1271 | const slice = tree.tokenSlice(line)[2..]; | 1273 | const slice = tree.tokenSlice(line); |
| 1272 | mem.copy(u8, bytes[i..], slice); | 1274 | mem.copy(u8, bytes[i..], slice[2..slice.len - 1]); |
| 1273 | i += slice.len; | 1275 | i += slice.len - 3; |
| 1274 | } | 1276 | } |
| 1275 | 1277 | ||
| 1276 | return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{}); | 1278 | return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{}); |
src-self-hosted/codegen.zig+11| ... | @@ -684,6 +684,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -684,6 +684,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 684 | .unreach => return MCValue{ .unreach = {} }, | 684 | .unreach => return MCValue{ .unreach = {} }, |
| 685 | .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?), | 685 | .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?), |
| 686 | .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), | 686 | .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), |
| 687 | .varptr => return self.genVarPtr(inst.castTag(.varptr).?), | ||
| 687 | } | 688 | } |
| 688 | } | 689 | } |
| 689 | 690 | ||
| ... | @@ -858,6 +859,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -858,6 +859,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 858 | } | 859 | } |
| 859 | } | 860 | } |
| 860 | 861 | ||
| 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 | |||
| 861 | fn reuseOperand(inst: *ir.Inst, op_index: ir.Inst.DeathsBitIndex, mcv: MCValue) bool { | 872 | fn reuseOperand(inst: *ir.Inst, op_index: ir.Inst.DeathsBitIndex, mcv: MCValue) bool { |
| 862 | if (!inst.operandDies(op_index) or !mcv.isMutable()) | 873 | if (!inst.operandDies(op_index) or !mcv.isMutable()) |
| 863 | return false; | 874 | return false; |
src-self-hosted/ir.zig+16| ... | @@ -81,6 +81,7 @@ pub const Inst = struct { | ... | @@ -81,6 +81,7 @@ pub const Inst = struct { |
| 81 | ref, | 81 | ref, |
| 82 | ret, | 82 | ret, |
| 83 | retvoid, | 83 | retvoid, |
| 84 | varptr, | ||
| 84 | /// Write a value to a pointer. LHS is pointer, RHS is value. | 85 | /// Write a value to a pointer. LHS is pointer, RHS is value. |
| 85 | store, | 86 | store, |
| 86 | sub, | 87 | sub, |
| ... | @@ -135,6 +136,7 @@ pub const Inst = struct { | ... | @@ -135,6 +136,7 @@ pub const Inst = struct { |
| 135 | .condbr => CondBr, | 136 | .condbr => CondBr, |
| 136 | .constant => Constant, | 137 | .constant => Constant, |
| 137 | .loop => Loop, | 138 | .loop => Loop, |
| 139 | .varptr => VarPtr, | ||
| 138 | }; | 140 | }; |
| 139 | } | 141 | } |
| 140 | 142 | ||
| ... | @@ -434,6 +436,20 @@ pub const Inst = struct { | ... | @@ -434,6 +436,20 @@ pub const Inst = struct { |
| 434 | return null; | 436 | return null; |
| 435 | } | 437 | } |
| 436 | }; | 438 | }; |
| 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 | }; | ||
| 437 | }; | 453 | }; |
| 438 | 454 | ||
| 439 | pub const Body = struct { | 455 | pub const Body = struct { |
src-self-hosted/type.zig+5-4| ... | @@ -457,7 +457,8 @@ pub const Type = extern union { | ... | @@ -457,7 +457,8 @@ pub const Type = extern union { |
| 457 | try param_type.format("", .{}, out_stream); | 457 | try param_type.format("", .{}, out_stream); |
| 458 | } | 458 | } |
| 459 | try out_stream.writeAll(") "); | 459 | try out_stream.writeAll(") "); |
| 460 | try payload.return_type.format("", .{}, out_stream); | 460 | ty = payload.return_type; |
| 461 | continue; | ||
| 461 | }, | 462 | }, |
| 462 | 463 | ||
| 463 | .array_u8 => { | 464 | .array_u8 => { |
| ... | @@ -1074,7 +1075,7 @@ pub const Type = extern union { | ... | @@ -1074,7 +1075,7 @@ pub const Type = extern union { |
| 1074 | } | 1075 | } |
| 1075 | 1076 | ||
| 1076 | /// Returns if type can be used for a runtime variable | 1077 | /// Returns if type can be used for a runtime variable |
| 1077 | pub fn isValidVarType(self: Type) bool { | 1078 | pub fn isValidVarType(self: Type, is_extern: bool) bool { |
| 1078 | var ty = self; | 1079 | var ty = self; |
| 1079 | while (true) switch (ty.zigTypeTag()) { | 1080 | while (true) switch (ty.zigTypeTag()) { |
| 1080 | .Bool, | 1081 | .Bool, |
| ... | @@ -1087,6 +1088,7 @@ pub const Type = extern union { | ... | @@ -1087,6 +1088,7 @@ pub const Type = extern union { |
| 1087 | .Vector, | 1088 | .Vector, |
| 1088 | => return true, | 1089 | => return true, |
| 1089 | 1090 | ||
| 1091 | .Opaque => return is_extern, | ||
| 1090 | .BoundFn, | 1092 | .BoundFn, |
| 1091 | .ComptimeFloat, | 1093 | .ComptimeFloat, |
| 1092 | .ComptimeInt, | 1094 | .ComptimeInt, |
| ... | @@ -1096,12 +1098,11 @@ pub const Type = extern union { | ... | @@ -1096,12 +1098,11 @@ pub const Type = extern union { |
| 1096 | .Void, | 1098 | .Void, |
| 1097 | .Undefined, | 1099 | .Undefined, |
| 1098 | .Null, | 1100 | .Null, |
| 1099 | .Opaque, | ||
| 1100 | => return false, | 1101 | => return false, |
| 1101 | 1102 | ||
| 1102 | .Optional => { | 1103 | .Optional => { |
| 1103 | var buf: Payload.Pointer = undefined; | 1104 | var buf: Payload.Pointer = undefined; |
| 1104 | return ty.optionalChild(&buf).isValidVarType(); | 1105 | return ty.optionalChild(&buf).isValidVarType(is_extern); |
| 1105 | }, | 1106 | }, |
| 1106 | .Pointer, .Array => ty = ty.elemType(), | 1107 | .Pointer, .Array => ty = ty.elemType(), |
| 1107 | 1108 |
src-self-hosted/value.zig+29-1| ... | @@ -79,6 +79,7 @@ pub const Value = extern union { | ... | @@ -79,6 +79,7 @@ pub const Value = extern union { |
| 79 | int_big_positive, | 79 | int_big_positive, |
| 80 | int_big_negative, | 80 | int_big_negative, |
| 81 | function, | 81 | function, |
| 82 | variable, | ||
| 82 | ref_val, | 83 | ref_val, |
| 83 | decl_ref, | 84 | decl_ref, |
| 84 | elem_ptr, | 85 | elem_ptr, |
| ... | @@ -196,6 +197,7 @@ pub const Value = extern union { | ... | @@ -196,6 +197,7 @@ pub const Value = extern union { |
| 196 | @panic("TODO implement copying of big ints"); | 197 | @panic("TODO implement copying of big ints"); |
| 197 | }, | 198 | }, |
| 198 | .function => return self.copyPayloadShallow(allocator, Payload.Function), | 199 | .function => return self.copyPayloadShallow(allocator, Payload.Function), |
| 200 | .variable => return self.copyPayloadShallow(allocator, Payload.Variable), | ||
| 199 | .ref_val => { | 201 | .ref_val => { |
| 200 | const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise); | 202 | const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise); |
| 201 | const new_payload = try allocator.create(Payload.RefVal); | 203 | const new_payload = try allocator.create(Payload.RefVal); |
| ... | @@ -216,7 +218,7 @@ pub const Value = extern union { | ... | @@ -216,7 +218,7 @@ pub const Value = extern union { |
| 216 | }; | 218 | }; |
| 217 | return Value{ .ptr_otherwise = &new_payload.base }; | 219 | return Value{ .ptr_otherwise = &new_payload.base }; |
| 218 | }, | 220 | }, |
| 219 | .enum_literal, .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes), | 221 | .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes), |
| 220 | .repeated => { | 222 | .repeated => { |
| 221 | const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise); | 223 | const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise); |
| 222 | const new_payload = try allocator.create(Payload.Repeated); | 224 | const new_payload = try allocator.create(Payload.Repeated); |
| ... | @@ -230,6 +232,15 @@ pub const Value = extern union { | ... | @@ -230,6 +232,15 @@ pub const Value = extern union { |
| 230 | .float_32 => return self.copyPayloadShallow(allocator, Payload.Float_32), | 232 | .float_32 => return self.copyPayloadShallow(allocator, Payload.Float_32), |
| 231 | .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64), | 233 | .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64), |
| 232 | .float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128), | 234 | .float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128), |
| 235 | .enum_literal => { | ||
| 236 | const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise); | ||
| 237 | const new_payload = try allocator.create(Payload.Bytes); | ||
| 238 | new_payload.* = .{ | ||
| 239 | .base = payload.base, | ||
| 240 | .data = try allocator.dupe(u8, payload.data), | ||
| 241 | }; | ||
| 242 | return Value{ .ptr_otherwise = &new_payload.base }; | ||
| 243 | }, | ||
| 233 | } | 244 | } |
| 234 | } | 245 | } |
| 235 | 246 | ||
| ... | @@ -310,6 +321,7 @@ pub const Value = extern union { | ... | @@ -310,6 +321,7 @@ pub const Value = extern union { |
| 310 | .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}), | 321 | .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}), |
| 311 | .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}), | 322 | .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}), |
| 312 | .function => return out_stream.writeAll("(function)"), | 323 | .function => return out_stream.writeAll("(function)"), |
| 324 | .variable => return out_stream.writeAll("(variable)"), | ||
| 313 | .ref_val => { | 325 | .ref_val => { |
| 314 | const ref_val = val.cast(Payload.RefVal).?; | 326 | const ref_val = val.cast(Payload.RefVal).?; |
| 315 | try out_stream.writeAll("&const "); | 327 | try out_stream.writeAll("&const "); |
| ... | @@ -410,6 +422,7 @@ pub const Value = extern union { | ... | @@ -410,6 +422,7 @@ pub const Value = extern union { |
| 410 | .int_big_positive, | 422 | .int_big_positive, |
| 411 | .int_big_negative, | 423 | .int_big_negative, |
| 412 | .function, | 424 | .function, |
| 425 | .variable, | ||
| 413 | .ref_val, | 426 | .ref_val, |
| 414 | .decl_ref, | 427 | .decl_ref, |
| 415 | .elem_ptr, | 428 | .elem_ptr, |
| ... | @@ -471,6 +484,7 @@ pub const Value = extern union { | ... | @@ -471,6 +484,7 @@ pub const Value = extern union { |
| 471 | .enum_literal_type, | 484 | .enum_literal_type, |
| 472 | .null_value, | 485 | .null_value, |
| 473 | .function, | 486 | .function, |
| 487 | .variable, | ||
| 474 | .ref_val, | 488 | .ref_val, |
| 475 | .decl_ref, | 489 | .decl_ref, |
| 476 | .elem_ptr, | 490 | .elem_ptr, |
| ... | @@ -548,6 +562,7 @@ pub const Value = extern union { | ... | @@ -548,6 +562,7 @@ pub const Value = extern union { |
| 548 | .enum_literal_type, | 562 | .enum_literal_type, |
| 549 | .null_value, | 563 | .null_value, |
| 550 | .function, | 564 | .function, |
| 565 | .variable, | ||
| 551 | .ref_val, | 566 | .ref_val, |
| 552 | .decl_ref, | 567 | .decl_ref, |
| 553 | .elem_ptr, | 568 | .elem_ptr, |
| ... | @@ -625,6 +640,7 @@ pub const Value = extern union { | ... | @@ -625,6 +640,7 @@ pub const Value = extern union { |
| 625 | .enum_literal_type, | 640 | .enum_literal_type, |
| 626 | .null_value, | 641 | .null_value, |
| 627 | .function, | 642 | .function, |
| 643 | .variable, | ||
| 628 | .ref_val, | 644 | .ref_val, |
| 629 | .decl_ref, | 645 | .decl_ref, |
| 630 | .elem_ptr, | 646 | .elem_ptr, |
| ... | @@ -728,6 +744,7 @@ pub const Value = extern union { | ... | @@ -728,6 +744,7 @@ pub const Value = extern union { |
| 728 | .enum_literal_type, | 744 | .enum_literal_type, |
| 729 | .null_value, | 745 | .null_value, |
| 730 | .function, | 746 | .function, |
| 747 | .variable, | ||
| 731 | .ref_val, | 748 | .ref_val, |
| 732 | .decl_ref, | 749 | .decl_ref, |
| 733 | .elem_ptr, | 750 | .elem_ptr, |
| ... | @@ -810,6 +827,7 @@ pub const Value = extern union { | ... | @@ -810,6 +827,7 @@ pub const Value = extern union { |
| 810 | .enum_literal_type, | 827 | .enum_literal_type, |
| 811 | .null_value, | 828 | .null_value, |
| 812 | .function, | 829 | .function, |
| 830 | .variable, | ||
| 813 | .ref_val, | 831 | .ref_val, |
| 814 | .decl_ref, | 832 | .decl_ref, |
| 815 | .elem_ptr, | 833 | .elem_ptr, |
| ... | @@ -974,6 +992,7 @@ pub const Value = extern union { | ... | @@ -974,6 +992,7 @@ pub const Value = extern union { |
| 974 | .bool_false, | 992 | .bool_false, |
| 975 | .null_value, | 993 | .null_value, |
| 976 | .function, | 994 | .function, |
| 995 | .variable, | ||
| 977 | .ref_val, | 996 | .ref_val, |
| 978 | .decl_ref, | 997 | .decl_ref, |
| 979 | .elem_ptr, | 998 | .elem_ptr, |
| ... | @@ -1046,6 +1065,7 @@ pub const Value = extern union { | ... | @@ -1046,6 +1065,7 @@ pub const Value = extern union { |
| 1046 | .enum_literal_type, | 1065 | .enum_literal_type, |
| 1047 | .null_value, | 1066 | .null_value, |
| 1048 | .function, | 1067 | .function, |
| 1068 | .variable, | ||
| 1049 | .ref_val, | 1069 | .ref_val, |
| 1050 | .decl_ref, | 1070 | .decl_ref, |
| 1051 | .elem_ptr, | 1071 | .elem_ptr, |
| ... | @@ -1182,6 +1202,7 @@ pub const Value = extern union { | ... | @@ -1182,6 +1202,7 @@ pub const Value = extern union { |
| 1182 | .bool_false, | 1202 | .bool_false, |
| 1183 | .null_value, | 1203 | .null_value, |
| 1184 | .function, | 1204 | .function, |
| 1205 | .variable, | ||
| 1185 | .int_u64, | 1206 | .int_u64, |
| 1186 | .int_i64, | 1207 | .int_i64, |
| 1187 | .int_big_positive, | 1208 | .int_big_positive, |
| ... | @@ -1260,6 +1281,7 @@ pub const Value = extern union { | ... | @@ -1260,6 +1281,7 @@ pub const Value = extern union { |
| 1260 | .bool_false, | 1281 | .bool_false, |
| 1261 | .null_value, | 1282 | .null_value, |
| 1262 | .function, | 1283 | .function, |
| 1284 | .variable, | ||
| 1263 | .int_u64, | 1285 | .int_u64, |
| 1264 | .int_i64, | 1286 | .int_i64, |
| 1265 | .int_big_positive, | 1287 | .int_big_positive, |
| ... | @@ -1355,6 +1377,7 @@ pub const Value = extern union { | ... | @@ -1355,6 +1377,7 @@ pub const Value = extern union { |
| 1355 | .bool_true, | 1377 | .bool_true, |
| 1356 | .bool_false, | 1378 | .bool_false, |
| 1357 | .function, | 1379 | .function, |
| 1380 | .variable, | ||
| 1358 | .int_u64, | 1381 | .int_u64, |
| 1359 | .int_i64, | 1382 | .int_i64, |
| 1360 | .int_big_positive, | 1383 | .int_big_positive, |
| ... | @@ -1429,6 +1452,11 @@ pub const Value = extern union { | ... | @@ -1429,6 +1452,11 @@ pub const Value = extern union { |
| 1429 | func: *Module.Fn, | 1452 | func: *Module.Fn, |
| 1430 | }; | 1453 | }; |
| 1431 | 1454 | ||
| 1455 | pub const Variable = struct { | ||
| 1456 | base: Payload = Payload{ .tag = .variable }, | ||
| 1457 | variable: *Module.Var, | ||
| 1458 | }; | ||
| 1459 | |||
| 1432 | pub const ArraySentinel0_u8_Type = struct { | 1460 | pub const ArraySentinel0_u8_Type = struct { |
| 1433 | base: Payload = Payload{ .tag = .array_sentinel_0_u8_type }, | 1461 | base: Payload = Payload{ .tag = .array_sentinel_0_u8_type }, |
| 1434 | len: u64, | 1462 | len: u64, |
src-self-hosted/zir.zig+70| ... | @@ -1752,6 +1752,9 @@ const EmitZIR = struct { | ... | @@ -1752,6 +1752,9 @@ const EmitZIR = struct { |
| 1752 | const decl_ref = try self.emitDeclRef(inst.src, declref.decl); | 1752 | const decl_ref = try self.emitDeclRef(inst.src, declref.decl); |
| 1753 | try new_body.instructions.append(decl_ref); | 1753 | try new_body.instructions.append(decl_ref); |
| 1754 | break :blk decl_ref; | 1754 | 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)); | ||
| 1755 | } else blk: { | 1758 | } else blk: { |
| 1756 | break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst; | 1759 | break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst; |
| 1757 | }; | 1760 | }; |
| ... | @@ -1875,6 +1878,11 @@ const EmitZIR = struct { | ... | @@ -1875,6 +1878,11 @@ const EmitZIR = struct { |
| 1875 | if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| { | 1878 | if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| { |
| 1876 | const decl = decl_ref.decl; | 1879 | const decl = decl_ref.decl; |
| 1877 | return try self.emitUnnamedDecl(try self.emitDeclRef(src, decl)); | 1880 | return try self.emitUnnamedDecl(try self.emitDeclRef(src, decl)); |
| 1881 | } else if (typed_value.val.cast(Value.Payload.Variable)) |variable| { | ||
| 1882 | return self.emitTypedValue(src, .{ | ||
| 1883 | .ty = typed_value.ty, | ||
| 1884 | .val = variable.variable.init, | ||
| 1885 | }); | ||
| 1878 | } | 1886 | } |
| 1879 | if (typed_value.val.isUndef()) { | 1887 | if (typed_value.val.isUndef()) { |
| 1880 | const as_inst = try self.arena.allocator.create(Inst.BinOp); | 1888 | const as_inst = try self.arena.allocator.create(Inst.BinOp); |
| ... | @@ -1964,6 +1972,21 @@ const EmitZIR = struct { | ... | @@ -1964,6 +1972,21 @@ const EmitZIR = struct { |
| 1964 | return self.emitPrimitive(src, .@"true") | 1972 | return self.emitPrimitive(src, .@"true") |
| 1965 | else | 1973 | else |
| 1966 | return self.emitPrimitive(src, .@"false"), | 1974 | return self.emitPrimitive(src, .@"false"), |
| 1975 | .EnumLiteral => { | ||
| 1976 | const enum_literal = @fieldParentPtr(Value.Payload.Bytes, "base", typed_value.val.ptr_otherwise); | ||
| 1977 | const inst = try self.arena.allocator.create(Inst.Str); | ||
| 1978 | inst.* = .{ | ||
| 1979 | .base = .{ | ||
| 1980 | .src = src, | ||
| 1981 | .tag = .enum_literal, | ||
| 1982 | }, | ||
| 1983 | .positionals = .{ | ||
| 1984 | .bytes = enum_literal.data, | ||
| 1985 | }, | ||
| 1986 | .kw_args = .{}, | ||
| 1987 | }; | ||
| 1988 | return self.emitUnnamedDecl(&inst.base); | ||
| 1989 | }, | ||
| 1967 | else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}), | 1990 | else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}), |
| 1968 | } | 1991 | } |
| 1969 | } | 1992 | } |
| ... | @@ -2311,6 +2334,8 @@ const EmitZIR = struct { | ... | @@ -2311,6 +2334,8 @@ const EmitZIR = struct { |
| 2311 | }; | 2334 | }; |
| 2312 | break :blk &new_inst.base; | 2335 | break :blk &new_inst.base; |
| 2313 | }, | 2336 | }, |
| 2337 | |||
| 2338 | .varptr => @panic("TODO"), | ||
| 2314 | }; | 2339 | }; |
| 2315 | try self.metadata.put(new_inst, .{ .deaths = inst.deaths }); | 2340 | try self.metadata.put(new_inst, .{ .deaths = inst.deaths }); |
| 2316 | try instructions.append(new_inst); | 2341 | try instructions.append(new_inst); |
| ... | @@ -2432,6 +2457,51 @@ const EmitZIR = struct { | ... | @@ -2432,6 +2457,51 @@ const EmitZIR = struct { |
| 2432 | }; | 2457 | }; |
| 2433 | return self.emitUnnamedDecl(&inst.base); | 2458 | return self.emitUnnamedDecl(&inst.base); |
| 2434 | }, | 2459 | }, |
| 2460 | .Array => { | ||
| 2461 | var len_pl = Value.Payload.Int_u64{ .int = ty.arrayLen() }; | ||
| 2462 | const len = Value.initPayload(&len_pl.base); | ||
| 2463 | |||
| 2464 | const inst = if (ty.arraySentinel()) |sentinel| blk: { | ||
| 2465 | const inst = try self.arena.allocator.create(Inst.ArrayTypeSentinel); | ||
| 2466 | inst.* = .{ | ||
| 2467 | .base = .{ | ||
| 2468 | .src = src, | ||
| 2469 | .tag = .array_type, | ||
| 2470 | }, | ||
| 2471 | .positionals = .{ | ||
| 2472 | .len = (try self.emitTypedValue(src, .{ | ||
| 2473 | .ty = Type.initTag(.usize), | ||
| 2474 | .val = len, | ||
| 2475 | })).inst, | ||
| 2476 | .sentinel = (try self.emitTypedValue(src, .{ | ||
| 2477 | .ty = ty.elemType(), | ||
| 2478 | .val = sentinel, | ||
| 2479 | })).inst, | ||
| 2480 | .elem_type = (try self.emitType(src, ty.elemType())).inst, | ||
| 2481 | }, | ||
| 2482 | .kw_args = .{}, | ||
| 2483 | }; | ||
| 2484 | break :blk &inst.base; | ||
| 2485 | } else blk: { | ||
| 2486 | const inst = try self.arena.allocator.create(Inst.BinOp); | ||
| 2487 | inst.* = .{ | ||
| 2488 | .base = .{ | ||
| 2489 | .src = src, | ||
| 2490 | .tag = .array_type, | ||
| 2491 | }, | ||
| 2492 | .positionals = .{ | ||
| 2493 | .lhs = (try self.emitTypedValue(src, .{ | ||
| 2494 | .ty = Type.initTag(.usize), | ||
| 2495 | .val = len, | ||
| 2496 | })).inst, | ||
| 2497 | .rhs = (try self.emitType(src, ty.elemType())).inst, | ||
| 2498 | }, | ||
| 2499 | .kw_args = .{}, | ||
| 2500 | }; | ||
| 2501 | break :blk &inst.base; | ||
| 2502 | }; | ||
| 2503 | return self.emitUnnamedDecl(inst); | ||
| 2504 | }, | ||
| 2435 | else => std.debug.panic("TODO implement emitType for {}", .{ty}), | 2505 | else => std.debug.panic("TODO implement emitType for {}", .{ty}), |
| 2436 | }, | 2506 | }, |
| 2437 | } | 2507 | } |
src-self-hosted/zir_sema.zig+3-4| ... | @@ -366,7 +366,7 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst. | ... | @@ -366,7 +366,7 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst. |
| 366 | fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 366 | fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 367 | const var_type = try resolveType(mod, scope, inst.positionals.operand); | 367 | const var_type = try resolveType(mod, scope, inst.positionals.operand); |
| 368 | // TODO this should happen only for var allocs | 368 | // TODO this should happen only for var allocs |
| 369 | if (!var_type.isValidVarType()) { | 369 | if (!var_type.isValidVarType(false)) { |
| 370 | return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type}); | 370 | return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type}); |
| 371 | } | 371 | } |
| 372 | const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type); | 372 | const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type); |
| ... | @@ -581,8 +581,7 @@ fn analyzeInstDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) Inne | ... | @@ -581,8 +581,7 @@ fn analyzeInstDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) Inne |
| 581 | 581 | ||
| 582 | fn analyzeInstDeclValInModule(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclValInModule) InnerError!*Inst { | 582 | fn analyzeInstDeclValInModule(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclValInModule) InnerError!*Inst { |
| 583 | const decl = inst.positionals.decl; | 583 | const decl = inst.positionals.decl; |
| 584 | const ptr = try mod.analyzeDeclRef(scope, inst.base.src, decl); | 584 | return mod.analyzeDeclRef(scope, inst.base.src, decl); |
| 585 | return mod.analyzeDeref(scope, inst.base.src, ptr, inst.base.src); | ||
| 586 | } | 585 | } |
| 587 | 586 | ||
| 588 | fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { | 587 | fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { |
| ... | @@ -779,7 +778,7 @@ fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inne | ... | @@ -779,7 +778,7 @@ fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inne |
| 779 | for (fntype.positionals.param_types) |param_type, i| { | 778 | for (fntype.positionals.param_types) |param_type, i| { |
| 780 | const resolved = try resolveType(mod, scope, param_type); | 779 | const resolved = try resolveType(mod, scope, param_type); |
| 781 | // TODO skip for comptime params | 780 | // TODO skip for comptime params |
| 782 | if (!resolved.isValidVarType()) { | 781 | if (!resolved.isValidVarType(false)) { |
| 783 | return mod.fail(scope, param_type.src, "parameter of type '{}' must be declared comptime", .{resolved}); | 782 | return mod.fail(scope, param_type.src, "parameter of type '{}' must be declared comptime", .{resolved}); |
| 784 | } | 783 | } |
| 785 | param_types[i] = resolved; | 784 | param_types[i] = resolved; |
test/stage2/compare_output.zig+33| ... | @@ -586,6 +586,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -586,6 +586,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 586 | "", | 586 | "", |
| 587 | ); | 587 | ); |
| 588 | 588 | ||
| 589 | // Character literals and multiline strings. | ||
| 589 | case.addCompareOutput( | 590 | case.addCompareOutput( |
| 590 | \\export fn _start() noreturn { | 591 | \\export fn _start() noreturn { |
| 591 | \\ const ignore = | 592 | \\ const ignore = |
| ... | @@ -617,6 +618,38 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -617,6 +618,38 @@ pub fn addCases(ctx: *TestContext) !void { |
| 617 | , | 618 | , |
| 618 | "", | 619 | "", |
| 619 | ); | 620 | ); |
| 621 | |||
| 622 | // Global const. | ||
| 623 | case.addCompareOutput( | ||
| 624 | \\export fn _start() noreturn { | ||
| 625 | \\ add(aa, bb); | ||
| 626 | \\ | ||
| 627 | \\ exit(); | ||
| 628 | \\} | ||
| 629 | \\ | ||
| 630 | \\const aa = 'ぁ'; | ||
| 631 | \\const bb = '\x03'; | ||
| 632 | \\ | ||
| 633 | \\fn add(a: u32, b: u32) void { | ||
| 634 | \\ assert(a + b == 12356); | ||
| 635 | \\} | ||
| 636 | \\ | ||
| 637 | \\pub fn assert(ok: bool) void { | ||
| 638 | \\ if (!ok) unreachable; // assertion failure | ||
| 639 | \\} | ||
| 640 | \\ | ||
| 641 | \\fn exit() noreturn { | ||
| 642 | \\ asm volatile ("syscall" | ||
| 643 | \\ : | ||
| 644 | \\ : [number] "{rax}" (231), | ||
| 645 | \\ [arg1] "{rdi}" (0) | ||
| 646 | \\ : "rcx", "r11", "memory" | ||
| 647 | \\ ); | ||
| 648 | \\ unreachable; | ||
| 649 | \\} | ||
| 650 | , | ||
| 651 | "", | ||
| 652 | ); | ||
| 620 | } | 653 | } |
| 621 | 654 | ||
| 622 | { | 655 | { |