AstGen: implement comptime locals

This commit is contained in:
Andrew Kelley 2021-04-21 20:42:49 -07:00
parent 8ee0cbe50a
commit ea00ddfe37
3 changed files with 60 additions and 54 deletions

View File

@ -1576,8 +1576,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
.addwrap,
.alloc,
.alloc_mut,
.alloc_comptime,
.alloc_inferred,
.alloc_inferred_mut,
.alloc_inferred_comptime,
.array_cat,
.array_mul,
.array_type,
@ -1665,7 +1667,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
.ptr_type,
.ptr_type_simple,
.enum_literal,
.enum_literal_small,
.merge_error_sets,
.error_union_type,
.bit_not,
@ -1901,9 +1902,6 @@ fn varDecl(
) InnerError!*Scope {
try emitDbgNode(gz, node);
const astgen = gz.astgen;
if (var_decl.comptime_token) |comptime_token| {
return astgen.failTok(comptime_token, "TODO implement comptime locals", .{});
}
if (var_decl.ast.align_node != 0) {
return astgen.failNode(var_decl.ast.align_node, "TODO implement alignment on locals", .{});
}
@ -1961,6 +1959,9 @@ fn varDecl(
switch (token_tags[var_decl.ast.mut_token]) {
.keyword_const => {
if (var_decl.comptime_token) |comptime_token| {
return astgen.failTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{});
}
// Depending on the type of AST the initialization expression is, we may need an lvalue
// or an rvalue as a result location. If it is an rvalue, we can use the instruction as
// the variable, no memory location needed.
@ -2062,17 +2063,19 @@ fn varDecl(
return &sub_scope.base;
},
.keyword_var => {
const is_comptime = var_decl.comptime_token != null;
var resolve_inferred_alloc: Zir.Inst.Ref = .none;
const var_data: struct {
result_loc: ResultLoc,
alloc: Zir.Inst.Ref,
} = if (var_decl.ast.type_node != 0) a: {
const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node);
const alloc = try gz.addUnNode(.alloc_mut, type_inst, node);
const tag: Zir.Inst.Tag = if (is_comptime) .alloc_comptime else .alloc_mut;
const alloc = try gz.addUnNode(tag, type_inst, node);
break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };
} else a: {
const alloc = try gz.addNode(.alloc_inferred_mut, node);
const tag: Zir.Inst.Tag = if (is_comptime) .alloc_inferred_comptime else .alloc_inferred_mut;
const alloc = try gz.addNode(tag, node);
resolve_inferred_alloc = alloc;
break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };
};

View File

@ -135,7 +135,9 @@ pub fn analyzeBody(
.alloc => try sema.zirAlloc(block, inst),
.alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
.alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
.alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst),
.alloc_mut => try sema.zirAllocMut(block, inst),
.alloc_comptime => try sema.zirAllocComptime(block, inst),
.array_cat => try sema.zirArrayCat(block, inst),
.array_mul => try sema.zirArrayMul(block, inst),
.array_type => try sema.zirArrayType(block, inst),
@ -177,7 +179,6 @@ pub fn analyzeBody(
.elem_val_node => try sema.zirElemValNode(block, inst),
.elem_type => try sema.zirElemType(block, inst),
.enum_literal => try sema.zirEnumLiteral(block, inst),
.enum_literal_small => try sema.zirEnumLiteralSmall(block, inst),
.enum_to_int => try sema.zirEnumToInt(block, inst),
.int_to_enum => try sema.zirIntToEnum(block, inst),
.err_union_code => try sema.zirErrUnionCode(block, inst),
@ -1130,6 +1131,18 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In
return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);
}
fn zirAllocComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
return sema.mod.fail(&block.base, src, "TODO implement Sema.zirAllocComptime", .{});
}
fn zirAllocInferredComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
const src_node = sema.code.instructions.items(.data)[inst].node;
const src: LazySrcLoc = .{ .node_offset = src_node };
return sema.mod.fail(&block.base, src, "TODO implement Sema.zirAllocInferredComptime", .{});
}
fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
@ -2334,19 +2347,6 @@ fn zirEnumLiteral(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerE
});
}
fn zirEnumLiteralSmall(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
const name = sema.code.instructions.items(.data)[inst].small_str.get();
const src: LazySrcLoc = .unneeded;
const duped_name = try sema.arena.dupe(u8, name);
return sema.mod.constInst(sema.arena, src, .{
.ty = Type.initTag(.enum_literal),
.val = try Value.Tag.enum_literal.create(sema.arena, duped_name),
});
}
fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
const mod = sema.mod;
const arena = sema.arena;

View File

@ -145,18 +145,6 @@ pub const Inst = struct {
/// Twos complement wrapping integer addition.
/// Uses the `pl_node` union field. Payload is `Bin`.
addwrap,
/// Allocates stack local memory.
/// Uses the `un_node` union field. The operand is the type of the allocated object.
/// The node source location points to a var decl node.
/// Indicates the beginning of a new statement in debug info.
alloc,
/// Same as `alloc` except mutable.
alloc_mut,
/// Same as `alloc` except the type is inferred.
/// Uses the `node` union field.
alloc_inferred,
/// Same as `alloc_inferred` except mutable.
alloc_inferred_mut,
/// Array concatenation. `a ++ b`
/// Uses the `pl_node` union field. Payload is `Bin`.
array_cat,
@ -483,12 +471,6 @@ pub const Inst = struct {
/// Create a pointer type which can have a sentinel, alignment, and/or bit range.
/// Uses the `ptr_type` union field.
ptr_type,
/// Each `store_to_inferred_ptr` puts the type of the stored value into a set,
/// and then `resolve_inferred_alloc` triggers peer type resolution on the set.
/// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which
/// is the allocation that needs to have its type inferred.
/// Uses the `un_node` field. The AST node is the var decl.
resolve_inferred_alloc,
/// Slice operation `lhs[rhs..]`. No sentinel and no end offset.
/// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceStart`.
slice_start,
@ -613,37 +595,40 @@ pub const Inst = struct {
ensure_err_payload_void,
/// An enum literal. Uses the `str_tok` union field.
enum_literal,
/// An enum literal 8 or fewer bytes. No source location.
/// Uses the `small_str` field.
enum_literal_small,
/// A switch expression. Uses the `pl_node` union field.
/// AST node is the switch, payload is `SwitchBlock`.
/// All prongs of target handled.
switch_block,
/// Same as switch_block, except one or more prongs have multiple items.
/// Payload is `SwitchBlockMulti`
switch_block_multi,
/// Same as switch_block, except has an else prong.
switch_block_else,
/// Same as switch_block_else, except one or more prongs have multiple items.
/// Payload is `SwitchBlockMulti`
switch_block_else_multi,
/// Same as switch_block, except has an underscore prong.
switch_block_under,
/// Same as switch_block, except one or more prongs have multiple items.
/// Payload is `SwitchBlockMulti`
switch_block_under_multi,
/// Same as `switch_block` but the target is a pointer to the value being switched on.
switch_block_ref,
/// Same as `switch_block_multi` but the target is a pointer to the value being switched on.
/// Payload is `SwitchBlockMulti`
switch_block_ref_multi,
/// Same as `switch_block_else` but the target is a pointer to the value being switched on.
switch_block_ref_else,
/// Same as `switch_block_else_multi` but the target is a pointer to the
/// value being switched on.
/// Payload is `SwitchBlockMulti`
switch_block_ref_else_multi,
/// Same as `switch_block_under` but the target is a pointer to the value
/// being switched on.
switch_block_ref_under,
/// Same as `switch_block_under_multi` but the target is a pointer to
/// the value being switched on.
/// Payload is `SwitchBlockMulti`
switch_block_ref_under_multi,
/// Produces the capture value for a switch prong.
/// Uses the `switch_capture` field.
@ -937,6 +922,32 @@ pub const Inst = struct {
/// Implements the `@cImport` builtin.
/// Uses the `pl_node` union field with payload `Block`.
c_import,
/// Allocates stack local memory.
/// Uses the `un_node` union field. The operand is the type of the allocated object.
/// The node source location points to a var decl node.
/// Indicates the beginning of a new statement in debug info.
alloc,
/// Same as `alloc` except mutable.
alloc_mut,
/// Allocates comptime-mutable memory.
/// Uses the `un_node` union field. The operand is the type of the allocated object.
/// The node source location points to a var decl node.
alloc_comptime,
/// Same as `alloc` except the type is inferred.
/// Uses the `node` union field.
alloc_inferred,
/// Same as `alloc_inferred` except mutable.
alloc_inferred_mut,
/// Same as `alloc_comptime` except the type is inferred.
alloc_inferred_comptime,
/// Each `store_to_inferred_ptr` puts the type of the stored value into a set,
/// and then `resolve_inferred_alloc` triggers peer type resolution on the set.
/// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which
/// is the allocation that needs to have its type inferred.
/// Uses the `un_node` field. The AST node is the var decl.
resolve_inferred_alloc,
/// The ZIR instruction tag is one of the `Extended` ones.
/// Uses the `extended` union field.
extended,
@ -949,8 +960,10 @@ pub const Inst = struct {
.addwrap,
.alloc,
.alloc_mut,
.alloc_comptime,
.alloc_inferred,
.alloc_inferred_mut,
.alloc_inferred_comptime,
.array_cat,
.array_mul,
.array_type,
@ -1066,7 +1079,6 @@ pub const Inst = struct {
.ptr_type_simple,
.ensure_err_payload_void,
.enum_literal,
.enum_literal_small,
.merge_error_sets,
.error_union_type,
.bit_not,
@ -2251,6 +2263,7 @@ const Writer = struct {
.alloc,
.alloc_mut,
.alloc_comptime,
.indexable_ptr_len,
.bit_not,
.bool_not,
@ -2516,6 +2529,7 @@ const Writer = struct {
.repeat_inline,
.alloc_inferred,
.alloc_inferred_mut,
.alloc_inferred_comptime,
=> try self.writeNode(stream, inst),
.error_value,
@ -2530,8 +2544,6 @@ const Writer = struct {
.@"unreachable" => try self.writeUnreachable(stream, inst),
.enum_literal_small => try self.writeSmallStr(stream, inst),
.switch_capture,
.switch_capture_ref,
.switch_capture_multi,
@ -3442,15 +3454,6 @@ const Writer = struct {
try self.writeSrc(stream, src);
}
fn writeSmallStr(
self: *Writer,
stream: anytype,
inst: Inst.Index,
) (@TypeOf(stream).Error || error{OutOfMemory})!void {
const str = self.code.instructions.items(.data)[inst].small_str.get();
try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)});
}
fn writeSwitchCapture(self: *Writer, stream: anytype, inst: Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[inst].switch_capture;
try self.writeInstIndex(stream, inst_data.switch_inst);