more comptime interpreter work
This commit is contained in:
parent
651955399e
commit
8828ff117d
@ -9,6 +9,7 @@ const ast = @import("ast.zig");
|
|||||||
const zig = std.zig;
|
const zig = std.zig;
|
||||||
const Ast = zig.Ast;
|
const Ast = zig.Ast;
|
||||||
const analysis = @import("analysis.zig");
|
const analysis = @import("analysis.zig");
|
||||||
|
const offsets = @import("offsets.zig");
|
||||||
const DocumentStore = @import("DocumentStore.zig");
|
const DocumentStore = @import("DocumentStore.zig");
|
||||||
|
|
||||||
pub const InternPool = @import("InternPool.zig");
|
pub const InternPool = @import("InternPool.zig");
|
||||||
@ -26,6 +27,8 @@ ip: InternPool = .{},
|
|||||||
document_store: *DocumentStore,
|
document_store: *DocumentStore,
|
||||||
uri: DocumentStore.Uri,
|
uri: DocumentStore.Uri,
|
||||||
scopes: std.MultiArrayList(Scope) = .{},
|
scopes: std.MultiArrayList(Scope) = .{},
|
||||||
|
decls: std.ArrayListUnmanaged(Decl) = .{},
|
||||||
|
namespaces: std.MultiArrayList(Namespace) = .{},
|
||||||
|
|
||||||
/// Interpreter diagnostic errors
|
/// Interpreter diagnostic errors
|
||||||
errors: std.AutoArrayHashMapUnmanaged(Ast.Node.Index, InterpreterError) = .{},
|
errors: std.AutoArrayHashMapUnmanaged(Ast.Node.Index, InterpreterError) = .{},
|
||||||
@ -56,10 +59,15 @@ pub fn deinit(interpreter: *ComptimeInterpreter) void {
|
|||||||
interpreter.ip.deinit(interpreter.allocator);
|
interpreter.ip.deinit(interpreter.allocator);
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < interpreter.scopes.len) : (i += 1) {
|
while (i < interpreter.namespaces.len) : (i += 1) {
|
||||||
interpreter.scopes.items(.child_scopes)[i].deinit(interpreter.allocator);
|
interpreter.namespaces.items(.decls)[i].deinit(interpreter.allocator);
|
||||||
|
interpreter.namespaces.items(.usingnamespaces)[i].deinit(interpreter.allocator);
|
||||||
}
|
}
|
||||||
|
interpreter.namespaces.deinit(interpreter.allocator);
|
||||||
|
interpreter.decls.deinit(interpreter.allocator);
|
||||||
interpreter.scopes.deinit(interpreter.allocator);
|
interpreter.scopes.deinit(interpreter.allocator);
|
||||||
|
|
||||||
|
interpreter.arena.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const Type = struct {
|
pub const Type = struct {
|
||||||
@ -77,6 +85,27 @@ pub const Value = struct {
|
|||||||
val: IPIndex,
|
val: IPIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Decl = struct {
|
||||||
|
name: []const u8,
|
||||||
|
ty: IPIndex,
|
||||||
|
val: IPIndex,
|
||||||
|
alignment: u16,
|
||||||
|
address_space: std.builtin.AddressSpace,
|
||||||
|
is_pub: bool,
|
||||||
|
is_exported: bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const NamespaceIndex = InternPool.NamespaceIndex;
|
||||||
|
|
||||||
|
pub const Namespace = struct {
|
||||||
|
/// always points to Namespace or Index.none
|
||||||
|
parent: NamespaceIndex,
|
||||||
|
/// Will be a struct, enum, union, or opaque.
|
||||||
|
// ty: Index,
|
||||||
|
decls: std.StringArrayHashMapUnmanaged(Decl) = .{},
|
||||||
|
usingnamespaces: std.ArrayListUnmanaged(NamespaceIndex) = .{},
|
||||||
|
};
|
||||||
|
|
||||||
// pub const Comptimeness = enum { @"comptime", runtime };
|
// pub const Comptimeness = enum { @"comptime", runtime };
|
||||||
|
|
||||||
pub const Scope = struct {
|
pub const Scope = struct {
|
||||||
@ -87,8 +116,7 @@ pub const Scope = struct {
|
|||||||
|
|
||||||
parent: u32, // zero indicates root scope
|
parent: u32, // zero indicates root scope
|
||||||
node_idx: Ast.Node.Index,
|
node_idx: Ast.Node.Index,
|
||||||
namespace: IPIndex,
|
namespace: NamespaceIndex,
|
||||||
child_scopes: std.ArrayListUnmanaged(u32) = .{},
|
|
||||||
|
|
||||||
pub const ScopeKind = enum { container, block, function };
|
pub const ScopeKind = enum { container, block, function };
|
||||||
pub fn scopeKind(scope: Scope) ScopeKind {
|
pub fn scopeKind(scope: Scope) ScopeKind {
|
||||||
@ -177,22 +205,19 @@ fn getDeclCount(tree: Ast, node_idx: Ast.Node.Index) usize {
|
|||||||
|
|
||||||
pub fn huntItDown(
|
pub fn huntItDown(
|
||||||
interpreter: *ComptimeInterpreter,
|
interpreter: *ComptimeInterpreter,
|
||||||
namespace: IPIndex,
|
namespace: NamespaceIndex,
|
||||||
decl_name: []const u8,
|
decl_name: []const u8,
|
||||||
options: InterpretOptions,
|
options: InterpretOptions,
|
||||||
) InterpretError!InternPool.Decl {
|
) InterpretError!Decl {
|
||||||
_ = options;
|
_ = options;
|
||||||
|
|
||||||
var current_namespace = namespace;
|
var current_namespace = namespace;
|
||||||
while (current_namespace != IPIndex.none) {
|
while (current_namespace != .none) {
|
||||||
const namespace_info = interpreter.ip.indexToKey(current_namespace).namespace;
|
const decls: std.StringArrayHashMapUnmanaged(Decl) = interpreter.namespaces.items(.decls)[@enumToInt(current_namespace)];
|
||||||
defer current_namespace = namespace_info.parent;
|
defer current_namespace = interpreter.namespaces.items(.parent)[@enumToInt(current_namespace)];
|
||||||
|
|
||||||
for (namespace_info.decls) |decl_index| {
|
if (decls.get(decl_name)) |decl| {
|
||||||
const decl_info = interpreter.ip.indexToKey(decl_index).declaration;
|
return decl;
|
||||||
if (std.mem.eql(u8, decl_info.name, decl_name)) {
|
|
||||||
return decl_info;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,45 +285,37 @@ pub fn interpret(
|
|||||||
.interpreter = interpreter,
|
.interpreter = interpreter,
|
||||||
.parent = scope,
|
.parent = scope,
|
||||||
.node_idx = node_idx,
|
.node_idx = node_idx,
|
||||||
.namespace = IPIndex.none, // declarations have not been resolved yet
|
.namespace = .none, // declarations have not been resolved yet
|
||||||
});
|
});
|
||||||
const container_scope = @intCast(u32, interpreter.scopes.len - 1);
|
const container_scope = @intCast(u32, interpreter.scopes.len - 1);
|
||||||
|
|
||||||
var fields = std.StringArrayHashMapUnmanaged(InternPool.Struct.Field){};
|
var fields = std.StringArrayHashMapUnmanaged(InternPool.Struct.Field){};
|
||||||
defer fields.deinit(interpreter.allocator);
|
|
||||||
|
|
||||||
var buffer: [2]Ast.Node.Index = undefined;
|
var buffer: [2]Ast.Node.Index = undefined;
|
||||||
const members = ast.declMembers(tree, node_idx, &buffer);
|
const members = ast.declMembers(tree, node_idx, &buffer);
|
||||||
for (members) |member| {
|
for (members) |member| {
|
||||||
const maybe_container_field: ?zig.Ast.full.ContainerField = switch (tags[member]) {
|
const container_field = ast.containerField(tree, member) orelse {
|
||||||
.container_field => tree.containerField(member),
|
|
||||||
.container_field_align => tree.containerFieldAlign(member),
|
|
||||||
.container_field_init => tree.containerFieldInit(member),
|
|
||||||
else => null,
|
|
||||||
};
|
|
||||||
|
|
||||||
const field_info = maybe_container_field orelse {
|
|
||||||
_ = try interpreter.interpret(member, container_scope, options);
|
_ = try interpreter.interpret(member, container_scope, options);
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
var init_type_value = try (try interpreter.interpret(field_info.ast.type_expr, container_scope, .{})).getValue();
|
var init_type_value = try (try interpreter.interpret(container_field.ast.type_expr, container_scope, .{})).getValue();
|
||||||
|
|
||||||
var default_value = if (field_info.ast.value_expr == 0)
|
var default_value = if (container_field.ast.value_expr == 0)
|
||||||
IPIndex.none
|
IPIndex.none
|
||||||
else
|
else
|
||||||
(try (try interpreter.interpret(field_info.ast.value_expr, container_scope, .{})).getValue()).val; // TODO check ty
|
(try (try interpreter.interpret(container_field.ast.value_expr, container_scope, .{})).getValue()).val; // TODO check ty
|
||||||
|
|
||||||
if (init_type_value.ty != type_type) {
|
if (init_type_value.ty != type_type) {
|
||||||
try interpreter.recordError(
|
try interpreter.recordError(
|
||||||
field_info.ast.type_expr,
|
container_field.ast.type_expr,
|
||||||
"expected_type",
|
"expected_type",
|
||||||
try std.fmt.allocPrint(interpreter.allocator, "expected type 'type', found '{}'", .{init_type_value.ty.fmtType(&interpreter.ip)}),
|
try std.fmt.allocPrint(interpreter.allocator, "expected type 'type', found '{}'", .{init_type_value.ty.fmtType(&interpreter.ip)}),
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = tree.tokenSlice(field_info.ast.main_token);
|
const name = tree.tokenSlice(container_field.ast.main_token);
|
||||||
|
|
||||||
const field: InternPool.Struct.Field = .{
|
const field: InternPool.Struct.Field = .{
|
||||||
.ty = init_type_value.val,
|
.ty = init_type_value.val,
|
||||||
@ -310,21 +327,12 @@ pub fn interpret(
|
|||||||
try fields.put(interpreter.arena.allocator(), name, field);
|
try fields.put(interpreter.arena.allocator(), name, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
const namespace = try interpreter.ip.get(interpreter.allocator, IPKey{
|
|
||||||
.namespace = .{
|
|
||||||
.parent = IPIndex.none,
|
|
||||||
// .ty = struct_type,
|
|
||||||
.decls = undefined, // TODO,
|
|
||||||
.usingnamespaces = &.{},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const struct_type = try interpreter.ip.get(interpreter.allocator, IPKey{
|
const struct_type = try interpreter.ip.get(interpreter.allocator, IPKey{
|
||||||
.struct_type = .{
|
.struct_type = .{
|
||||||
.fields = fields,
|
.fields = fields,
|
||||||
.namespace = namespace, // TODO
|
.namespace = .none, // TODO
|
||||||
.layout = std.builtin.Type.ContainerLayout.Auto, // TODO
|
.layout = .Auto, // TODO
|
||||||
.backing_int_ty = IPIndex.none, // TODO
|
.backing_int_ty = .none, // TODO
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -372,7 +380,7 @@ pub fn interpret(
|
|||||||
.interpreter = interpreter,
|
.interpreter = interpreter,
|
||||||
.parent = scope,
|
.parent = scope,
|
||||||
.node_idx = node_idx,
|
.node_idx = node_idx,
|
||||||
.namespace = IPIndex.none,
|
.namespace = .none,
|
||||||
});
|
});
|
||||||
const block_scope = @intCast(u32, interpreter.scopes.len - 1);
|
const block_scope = @intCast(u32, interpreter.scopes.len - 1);
|
||||||
|
|
||||||
@ -493,7 +501,7 @@ pub fn interpret(
|
|||||||
var ir = try interpreter.interpret(data[node_idx].lhs, scope, options);
|
var ir = try interpreter.interpret(data[node_idx].lhs, scope, options);
|
||||||
var irv = try ir.getValue();
|
var irv = try ir.getValue();
|
||||||
|
|
||||||
const namespace = interpreter.ip.indexToKey(irv.val).getNamespace() orelse return error.IdentifierNotFound;
|
const namespace = interpreter.ip.indexToKey(irv.val).getNamespace();
|
||||||
|
|
||||||
var scope_sub_decl = irv.interpreter.huntItDown(namespace, rhs_str, options) catch |err| {
|
var scope_sub_decl = irv.interpreter.huntItDown(namespace, rhs_str, options) catch |err| {
|
||||||
if (err == error.IdentifierNotFound) try interpreter.recordError(
|
if (err == error.IdentifierNotFound) try interpreter.recordError(
|
||||||
@ -688,7 +696,7 @@ pub fn interpret(
|
|||||||
.node_idx = node_idx,
|
.node_idx = node_idx,
|
||||||
.ty = try interpreter.ip.get(interpreter.allocator, IPKey{ .struct_type = .{
|
.ty = try interpreter.ip.get(interpreter.allocator, IPKey{ .struct_type = .{
|
||||||
.fields = .{},
|
.fields = .{},
|
||||||
.namespace = IPIndex.none,
|
.namespace = .none,
|
||||||
.layout = .Auto,
|
.layout = .Auto,
|
||||||
.backing_int_ty = IPIndex.none,
|
.backing_int_ty = IPIndex.none,
|
||||||
} }),
|
} }),
|
||||||
@ -735,15 +743,13 @@ pub fn interpret(
|
|||||||
if (value.ty != type_type) return error.InvalidBuiltin;
|
if (value.ty != type_type) return error.InvalidBuiltin;
|
||||||
if (interpreter.ip.indexToKey(field_name.ty) != .pointer_type) return error.InvalidBuiltin; // Check if it's a []const u8
|
if (interpreter.ip.indexToKey(field_name.ty) != .pointer_type) return error.InvalidBuiltin; // Check if it's a []const u8
|
||||||
|
|
||||||
const namespace_index = interpreter.ip.indexToKey(value.val).getNamespace() orelse return error.InvalidBuiltin;
|
const namespace = interpreter.ip.indexToKey(value.val).getNamespace();
|
||||||
const namespace = interpreter.ip.indexToKey(namespace_index).namespace;
|
if (namespace == .none) return error.InvalidBuiltin;
|
||||||
|
|
||||||
const name = interpreter.ip.indexToKey(field_name.val).bytes.data; // TODO add checks
|
const name = interpreter.ip.indexToKey(field_name.val).bytes.data; // TODO add checks
|
||||||
|
|
||||||
const has_decl = for (namespace.decls) |decl| {
|
const decls = interpreter.namespaces.items(.decls)[@enumToInt(namespace)];
|
||||||
const decl_name = interpreter.ip.indexToKey(decl).declaration.name;
|
const has_decl = decls.contains(name);
|
||||||
if (std.mem.eql(u8, decl_name, name)) break true;
|
|
||||||
} else false;
|
|
||||||
|
|
||||||
return InterpretResult{ .value = Value{
|
return InterpretResult{ .value = Value{
|
||||||
.interpreter = interpreter,
|
.interpreter = interpreter,
|
||||||
@ -812,24 +818,22 @@ pub fn interpret(
|
|||||||
.@"comptime" => {
|
.@"comptime" => {
|
||||||
return try interpreter.interpret(data[node_idx].lhs, scope, .{});
|
return try interpreter.interpret(data[node_idx].lhs, scope, .{});
|
||||||
},
|
},
|
||||||
// .fn_proto,
|
.fn_proto, .fn_proto_multi, .fn_proto_one, .fn_proto_simple, .fn_decl => {
|
||||||
// .fn_proto_multi,
|
var buf: [1]Ast.Node.Index = undefined;
|
||||||
// .fn_proto_one,
|
const func = ast.fnProto(tree, node_idx, &buf).?;
|
||||||
// .fn_proto_simple,
|
|
||||||
.fn_decl => {
|
|
||||||
// var buf: [1]Ast.Node.Index = undefined;
|
|
||||||
// const func = ast.fnProto(tree, node_idx, &buf).?;
|
|
||||||
|
|
||||||
// TODO: Resolve function type
|
// TODO: Resolve function type
|
||||||
|
|
||||||
// const function_type = try interpreter.ip.get(interpreter.allocator, IPKey{ .function_type = .{
|
const type_type = try interpreter.ip.get(interpreter.allocator, IPKey{ .simple = .type });
|
||||||
// .calling_convention = .Unspecified,
|
|
||||||
// .alignment = 0,
|
const function_type = try interpreter.ip.get(interpreter.allocator, IPKey{ .function_type = .{
|
||||||
// .is_generic = false,
|
.calling_convention = .Unspecified,
|
||||||
// .is_var_args = false,
|
.alignment = 0,
|
||||||
// .return_type = IPIndex.none,
|
.is_generic = false,
|
||||||
// .args = &.{},
|
.is_var_args = false,
|
||||||
// } });
|
.return_type = IPIndex.none,
|
||||||
|
.args = &.{},
|
||||||
|
} });
|
||||||
|
|
||||||
// var it = func.iterate(&tree);
|
// var it = func.iterate(&tree);
|
||||||
// while (ast.nextFnParam(&it)) |param| {
|
// while (ast.nextFnParam(&it)) |param| {
|
||||||
@ -855,21 +859,21 @@ pub fn interpret(
|
|||||||
// if ((try interpreter.interpret(func.ast.return_type, func_scope_idx, .{ .observe_values = true, .is_comptime = true })).maybeGetValue()) |value|
|
// if ((try interpreter.interpret(func.ast.return_type, func_scope_idx, .{ .observe_values = true, .is_comptime = true })).maybeGetValue()) |value|
|
||||||
// fnd.return_type = value.value_data.@"type";
|
// fnd.return_type = value.value_data.@"type";
|
||||||
|
|
||||||
// var value = Value{
|
const name = offsets.tokenToSlice(tree, func.name_token.?);
|
||||||
// .interpreter = interpreter,
|
|
||||||
// .node_idx = node_idx,
|
|
||||||
// .ty = function_type,
|
|
||||||
// .val = IPIndex.none, // TODO
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const name = analysis.getDeclName(tree, node_idx).?;
|
const namespace = interpreter.scopes.items(.namespace)[scope];
|
||||||
// var namespace = interpreter.ip.indexToKey(scope.?.namespace).namespace;
|
if (namespace != .none) {
|
||||||
// try namespace.decls.put(interpreter.allocator, name, .{
|
const decls = &interpreter.namespaces.items(.decls)[@enumToInt(namespace)];
|
||||||
// .scope = scope.?,
|
try decls.put(interpreter.allocator, name, .{
|
||||||
// .node_idx = node_idx,
|
.name = name,
|
||||||
// .name = name,
|
.ty = type_type,
|
||||||
// .value = value,
|
.val = function_type,
|
||||||
// });
|
.alignment = 0, // TODO
|
||||||
|
.address_space = .generic, // TODO
|
||||||
|
.is_pub = false, // TODO
|
||||||
|
.is_exported = false, // TODO
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return InterpretResult{ .nothing = {} };
|
return InterpretResult{ .nothing = {} };
|
||||||
},
|
},
|
||||||
@ -889,7 +893,7 @@ pub fn interpret(
|
|||||||
defer args.deinit(interpreter.allocator);
|
defer args.deinit(interpreter.allocator);
|
||||||
|
|
||||||
for (call_full.ast.params) |param| {
|
for (call_full.ast.params) |param| {
|
||||||
try args.append(interpreter.allocator, try (try interpreter.interpret(param, scope, .{})).getValue());
|
args.appendAssumeCapacity(try (try interpreter.interpret(param, scope, .{})).getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
const func_id_result = try interpreter.interpret(call_full.ast.fn_expr, scope, .{});
|
const func_id_result = try interpreter.interpret(call_full.ast.fn_expr, scope, .{});
|
||||||
@ -1008,7 +1012,7 @@ pub fn call(
|
|||||||
.interpreter = interpreter,
|
.interpreter = interpreter,
|
||||||
.parent = scope,
|
.parent = scope,
|
||||||
.node_idx = func_node_idx,
|
.node_idx = func_node_idx,
|
||||||
.namespace = IPIndex.none,
|
.namespace = .none,
|
||||||
});
|
});
|
||||||
const fn_scope = @intCast(u32, interpreter.scopes.len - 1);
|
const fn_scope = @intCast(u32, interpreter.scopes.len - 1);
|
||||||
|
|
||||||
|
@ -519,7 +519,7 @@ pub const Key = union(enum) {
|
|||||||
.optional_type => |optional_info| {
|
.optional_type => |optional_info| {
|
||||||
const child_ty = optional_info.payload_type;
|
const child_ty = optional_info.payload_type;
|
||||||
const child_key = ip.indexToKey(child_ty);
|
const child_key = ip.indexToKey(child_ty);
|
||||||
if(child_key != .pointer_type) return false;
|
if (child_key != .pointer_type) return false;
|
||||||
const info = child_key.pointer_type;
|
const info = child_key.pointer_type;
|
||||||
switch (info.size) {
|
switch (info.size) {
|
||||||
.Slice, .C => return false,
|
.Slice, .C => return false,
|
||||||
@ -533,7 +533,7 @@ pub const Key = union(enum) {
|
|||||||
|
|
||||||
pub fn elemType2(ty: Key) Index {
|
pub fn elemType2(ty: Key) Index {
|
||||||
return switch (ty) {
|
return switch (ty) {
|
||||||
.simple => |simple| switch(simple) {
|
.simple => |simple| switch (simple) {
|
||||||
.@"anyframe" => @panic("TODO: return void type"),
|
.@"anyframe" => @panic("TODO: return void type"),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
@ -1544,7 +1544,7 @@ pub fn resolvePeerTypes(ip: *InternPool, gpa: Allocator, types: []const Index, t
|
|||||||
return Index.none;
|
return Index.none;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(chosen == .none) return chosen;
|
if (chosen == .none) return chosen;
|
||||||
const chosen_key = ip.indexToKey(chosen);
|
const chosen_key = ip.indexToKey(chosen);
|
||||||
|
|
||||||
if (convert_to_slice) {
|
if (convert_to_slice) {
|
||||||
@ -2214,8 +2214,8 @@ fn coerceInMemoryAllowedPtrs(
|
|||||||
const ok_sent = dest_info.sentinel == .none or src_info.size == .C or dest_info.sentinel == src_info.sentinel; // is this enough for a value equality check?
|
const ok_sent = dest_info.sentinel == .none or src_info.size == .C or dest_info.sentinel == src_info.sentinel; // is this enough for a value equality check?
|
||||||
if (!ok_sent) {
|
if (!ok_sent) {
|
||||||
return InMemoryCoercionResult{ .ptr_sentinel = .{
|
return InMemoryCoercionResult{ .ptr_sentinel = .{
|
||||||
.actual = if(src_info.sentinel != .none) src_info.sentinel else try ip.get(gpa, .{.simple = .unreachable_value}),
|
.actual = if (src_info.sentinel != .none) src_info.sentinel else try ip.get(gpa, .{ .simple = .unreachable_value }),
|
||||||
.wanted = if(dest_info.sentinel != .none) dest_info.sentinel else try ip.get(gpa, .{.simple = .unreachable_value}),
|
.wanted = if (dest_info.sentinel != .none) dest_info.sentinel else try ip.get(gpa, .{ .simple = .unreachable_value }),
|
||||||
.ty = dest_info.elem_type,
|
.ty = dest_info.elem_type,
|
||||||
} };
|
} };
|
||||||
}
|
}
|
||||||
@ -2227,8 +2227,7 @@ fn coerceInMemoryAllowedPtrs(
|
|||||||
alignment: {
|
alignment: {
|
||||||
if (src_info.alignment == 0 and dest_info.alignment == 0 and
|
if (src_info.alignment == 0 and dest_info.alignment == 0 and
|
||||||
dest_info.elem_type == src_info.elem_type // is this enough for a value equality check?
|
dest_info.elem_type == src_info.elem_type // is this enough for a value equality check?
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
break :alignment;
|
break :alignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user