Skip to content

Commit

Permalink
Merge pull request #21264 from mlugg/decl-literals
Browse files Browse the repository at this point in the history
compiler: implement decl literals
  • Loading branch information
mlugg authored Sep 1, 2024
2 parents 227fb48 + 0b9fccf commit 6d2945f
Show file tree
Hide file tree
Showing 17 changed files with 336 additions and 15 deletions.
8 changes: 8 additions & 0 deletions lib/std/array_hash_map.zig
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,8 @@ pub fn ArrayHashMap(
/// `store_hash` is `false` and the number of entries in the map is less than 9,
/// the overhead cost of using `ArrayHashMapUnmanaged` rather than `std.ArrayList` is
/// only a single pointer-sized integer.
///
/// Default initialization of this struct is deprecated; use `.empty` instead.
pub fn ArrayHashMapUnmanaged(
comptime K: type,
comptime V: type,
Expand Down Expand Up @@ -538,6 +540,12 @@ pub fn ArrayHashMapUnmanaged(
/// Used to detect memory safety violations.
pointer_stability: std.debug.SafetyLock = .{},

/// A map containing no keys or values.
pub const empty: Self = .{
.entries = .{},
.index_header = null,
};

/// Modifying the key is allowed only if it does not change the hash.
/// Modifying the value is allowed.
/// Entry pointers become invalid whenever this ArrayHashMap is modified,
Expand Down
8 changes: 8 additions & 0 deletions lib/std/array_list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,8 @@ pub fn ArrayListUnmanaged(comptime T: type) type {
/// Functions that potentially allocate memory accept an `Allocator` parameter.
/// Initialize directly or with `initCapacity`, and deinitialize with `deinit`
/// or use `toOwnedSlice`.
///
/// Default initialization of this struct is deprecated; use `.empty` instead.
pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type {
if (alignment) |a| {
if (a == @alignOf(T)) {
Expand All @@ -638,6 +640,12 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
/// additional memory.
capacity: usize = 0,

/// An ArrayList containing no elements.
pub const empty: Self = .{
.items = &.{},
.capacity = 0,
};

pub const Slice = if (alignment) |a| ([]align(a) T) else []T;

pub fn SentinelSlice(comptime s: T) type {
Expand Down
9 changes: 9 additions & 0 deletions lib/std/hash_map.zig
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,8 @@ pub fn HashMap(
/// the price of handling size with u32, which should be reasonable enough
/// for almost all uses.
/// Deletions are achieved with tombstones.
///
/// Default initialization of this struct is deprecated; use `.empty` instead.
pub fn HashMapUnmanaged(
comptime K: type,
comptime V: type,
Expand Down Expand Up @@ -762,6 +764,13 @@ pub fn HashMapUnmanaged(
/// Capacity of the first grow when bootstrapping the hashmap.
const minimal_capacity = 8;

/// A map containing no keys or values.
pub const empty: Self = .{
.metadata = null,
.size = 0,
.available = 0,
};

// This hashmap is specially designed for sizes that fit in a u32.
pub const Size = u32;

Expand Down
11 changes: 11 additions & 0 deletions lib/std/heap/general_purpose_allocator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ pub const Config = struct {

pub const Check = enum { ok, leak };

/// Default initialization of this struct is deprecated; use `.init` instead.
pub fn GeneralPurposeAllocator(comptime config: Config) type {
return struct {
backing_allocator: Allocator = std.heap.page_allocator,
Expand All @@ -174,6 +175,16 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {

const Self = @This();

/// The initial state of a `GeneralPurposeAllocator`, containing no allocations and backed by the system page allocator.
pub const init: Self = .{
.backing_allocator = std.heap.page_allocator,
.buckets = [1]Buckets{.{}} ** small_bucket_count,
.cur_buckets = [1]?*BucketHeader{null} ** small_bucket_count,
.large_allocations = .{},
.empty_buckets = if (config.retain_metadata) .{} else {},
.bucket_node_pool = .init(std.heap.page_allocator),
};

const total_requested_bytes_init = if (config.enable_memory_limit) @as(usize, 0) else {};
const requested_memory_limit_init = if (config.enable_memory_limit) @as(usize, math.maxInt(usize)) else {};

Expand Down
49 changes: 43 additions & 6 deletions lib/std/zig/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1028,7 +1028,18 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
return blockExpr(gz, scope, ri, node, statements, .normal);
},
.enum_literal => return simpleStrTok(gz, ri, main_tokens[node], node, .enum_literal),
.enum_literal => if (try ri.rl.resultType(gz, node)) |res_ty| {
const str_index = try astgen.identAsString(main_tokens[node]);
const res = try gz.addPlNode(.decl_literal, node, Zir.Inst.Field{
.lhs = res_ty,
.field_name_start = str_index,
});
switch (ri.rl) {
.discard, .none, .ref => unreachable, // no result type
.ty, .coerced_ty => return res, // `decl_literal` does the coercion for us
.ref_coerced_ty, .ptr, .inferred_ptr, .destructure => return rvalue(gz, ri, res, node),
}
} else return simpleStrTok(gz, ri, main_tokens[node], node, .enum_literal),
.error_value => return simpleStrTok(gz, ri, node_datas[node].rhs, node, .error_value),
// TODO restore this when implementing https://github.com/ziglang/zig/issues/6025
// .anyframe_literal => return rvalue(gz, ri, .anyframe_type, node),
Expand Down Expand Up @@ -2752,6 +2763,8 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.err_union_code_ptr,
.ptr_type,
.enum_literal,
.decl_literal,
.decl_literal_no_coerce,
.merge_error_sets,
.error_union_type,
.bit_not,
Expand Down Expand Up @@ -2914,6 +2927,8 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.validate_array_init_result_ty,
.validate_ptr_array_init,
.validate_ref_ty,
.try_operand_ty,
.try_ref_operand_ty,
=> break :b true,

.@"defer" => unreachable,
Expand Down Expand Up @@ -5887,13 +5902,21 @@ fn tryExpr(
}
const try_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };

const operand_ri: ResultInfo = switch (ri.rl) {
.ref, .ref_coerced_ty => .{ .rl = .ref, .ctx = .error_handling_expr },
else => .{ .rl = .none, .ctx = .error_handling_expr },
const operand_rl: ResultInfo.Loc, const block_tag: Zir.Inst.Tag = switch (ri.rl) {
.ref => .{ .ref, .try_ptr },
.ref_coerced_ty => |payload_ptr_ty| .{
.{ .ref_coerced_ty = try parent_gz.addUnNode(.try_ref_operand_ty, payload_ptr_ty, node) },
.try_ptr,
},
else => if (try ri.rl.resultType(parent_gz, node)) |payload_ty| .{
// `coerced_ty` is OK due to the `rvalue` call below
.{ .coerced_ty = try parent_gz.addUnNode(.try_operand_ty, payload_ty, node) },
.@"try",
} else .{ .none, .@"try" },
};
const operand_ri: ResultInfo = .{ .rl = operand_rl, .ctx = .error_handling_expr };
// This could be a pointer or value depending on the `ri` parameter.
const operand = try reachableExpr(parent_gz, scope, operand_ri, operand_node, node);
const block_tag: Zir.Inst.Tag = if (operand_ri.rl == .ref) .try_ptr else .@"try";
const try_inst = try parent_gz.makeBlockInst(block_tag, node);
try parent_gz.instructions.append(astgen.gpa, try_inst);

Expand Down Expand Up @@ -9905,7 +9928,7 @@ fn callExpr(
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;

const callee = try calleeExpr(gz, scope, call.ast.fn_expr);
const callee = try calleeExpr(gz, scope, ri.rl, call.ast.fn_expr);
const modifier: std.builtin.CallModifier = blk: {
if (gz.is_comptime) {
break :blk .compile_time;
Expand Down Expand Up @@ -10033,6 +10056,7 @@ const Callee = union(enum) {
fn calleeExpr(
gz: *GenZir,
scope: *Scope,
call_rl: ResultInfo.Loc,
node: Ast.Node.Index,
) InnerError!Callee {
const astgen = gz.astgen;
Expand All @@ -10059,6 +10083,19 @@ fn calleeExpr(
.field_name_start = str_index,
} };
},
.enum_literal => if (try call_rl.resultType(gz, node)) |res_ty| {
// Decl literal call syntax, e.g.
// `const foo: T = .init();`
// Look up `init` in `T`, but don't try and coerce it.
const str_index = try astgen.identAsString(tree.nodes.items(.main_token)[node]);
const callee = try gz.addPlNode(.decl_literal_no_coerce, node, Zir.Inst.Field{
.lhs = res_ty,
.field_name_start = str_index,
});
return .{ .direct = callee };
} else {
return .{ .direct = try expr(gz, scope, .{ .rl = .none }, node) };
},
else => return .{ .direct = try expr(gz, scope, .{ .rl = .none }, node) },
}
}
Expand Down
32 changes: 32 additions & 0 deletions lib/std/zig/Zir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,14 @@ pub const Inst = struct {
err_union_code_ptr,
/// An enum literal. Uses the `str_tok` union field.
enum_literal,
/// A decl literal. This is similar to `field`, but unwraps error unions and optionals,
/// and coerces the result to the given type.
/// Uses the `pl_node` union field. Payload is `Field`.
decl_literal,
/// The same as `decl_literal`, but the coercion is omitted. This is used for decl literal
/// function call syntax, i.e. `.foo()`.
/// Uses the `pl_node` union field. Payload is `Field`.
decl_literal_no_coerce,
/// A switch expression. Uses the `pl_node` union field.
/// AST node is the switch, payload is `SwitchBlock`.
switch_block,
Expand Down Expand Up @@ -684,6 +692,14 @@ pub const Inst = struct {
/// operator. Emit a compile error if not.
/// Uses the `un_tok` union field. Token is the `&` operator. Operand is the type.
validate_ref_ty,
/// Given a type `T`, construct the type `E!T`, where `E` is this function's error set, to be used
/// as the result type of a `try` operand. Generic poison is propagated.
/// Uses the `un_node` union field. Node is the `try` expression. Operand is the type `T`.
try_operand_ty,
/// Given a type `*T`, construct the type `*E!T`, where `E` is this function's error set, to be used
/// as the result type of a `try` operand whose address is taken with `&`. Generic poison is propagated.
/// Uses the `un_node` union field. Node is the `try` expression. Operand is the type `*T`.
try_ref_operand_ty,

// The following tags all relate to struct initialization expressions.

Expand Down Expand Up @@ -1136,6 +1152,8 @@ pub const Inst = struct {
.err_union_code_ptr,
.ptr_type,
.enum_literal,
.decl_literal,
.decl_literal_no_coerce,
.merge_error_sets,
.error_union_type,
.bit_not,
Expand Down Expand Up @@ -1254,6 +1272,8 @@ pub const Inst = struct {
.array_init_elem_type,
.array_init_elem_ptr,
.validate_ref_ty,
.try_operand_ty,
.try_ref_operand_ty,
.restore_err_ret_index_unconditional,
.restore_err_ret_index_fn_entry,
=> false,
Expand Down Expand Up @@ -1324,6 +1344,8 @@ pub const Inst = struct {
.validate_array_init_result_ty,
.validate_ptr_array_init,
.validate_ref_ty,
.try_operand_ty,
.try_ref_operand_ty,
=> true,

.param,
Expand Down Expand Up @@ -1430,6 +1452,8 @@ pub const Inst = struct {
.err_union_code_ptr,
.ptr_type,
.enum_literal,
.decl_literal,
.decl_literal_no_coerce,
.merge_error_sets,
.error_union_type,
.bit_not,
Expand Down Expand Up @@ -1685,6 +1709,8 @@ pub const Inst = struct {
.err_union_code = .un_node,
.err_union_code_ptr = .un_node,
.enum_literal = .str_tok,
.decl_literal = .pl_node,
.decl_literal_no_coerce = .pl_node,
.switch_block = .pl_node,
.switch_block_ref = .pl_node,
.switch_block_err_union = .pl_node,
Expand All @@ -1698,6 +1724,8 @@ pub const Inst = struct {
.opt_eu_base_ptr_init = .un_node,
.coerce_ptr_elem_ty = .pl_node,
.validate_ref_ty = .un_tok,
.try_operand_ty = .un_node,
.try_ref_operand_ty = .un_node,

.int_from_ptr = .un_node,
.compile_error = .un_node,
Expand Down Expand Up @@ -3828,12 +3856,16 @@ fn findDeclsInner(
.err_union_code,
.err_union_code_ptr,
.enum_literal,
.decl_literal,
.decl_literal_no_coerce,
.validate_deref,
.validate_destructure,
.field_type_ref,
.opt_eu_base_ptr_init,
.coerce_ptr_elem_ty,
.validate_ref_ty,
.try_operand_ty,
.try_ref_operand_ty,
.struct_init_empty,
.struct_init_empty_result,
.struct_init_empty_ref_result,
Expand Down
Loading

0 comments on commit 6d2945f

Please sign in to comment.