fix remaining compiler errors

This commit is contained in:
Techatrix 2022-12-27 03:02:07 +01:00
parent 03e50066a1
commit 6118686d00
4 changed files with 232 additions and 263 deletions

View File

@ -77,93 +77,6 @@ pub const Value = struct {
val: IPIndex,
};
pub const FieldDefinition = struct {
node_idx: Ast.Node.Index,
/// Store name so tree doesn't need to be used to access field name
/// When the field is a tuple field, `name` will be an empty slice
name: []const u8,
ty: Type,
default_value: ?Value,
};
pub const Declaration = struct {
scope: u32,
node_idx: Ast.Node.Index,
/// Store name so tree doesn't need to be used to access declaration name
name: []const u8,
/// If value is null, declaration has not been interpreted yet
value: ?Value = null,
// TODO: figure this out
// pub const DeclarationKind = enum{variable, function};
// pub fn declarationKind(declaration: Declaration, tree: Ast) DeclarationKind {
// return switch(tree.nodes.items(.tag)[declaration.node_idx]) {
// .fn_proto,
// .fn_proto_one,
// .fn_proto_simple,
// .fn_proto_multi,
// .fn_decl
// }
// }
pub fn getValue(decl: *Declaration) InterpretError!Value {
var interpreter = decl.scope.interpreter;
const tree = decl.scope.interpreter.getHandle().tree;
const tags = tree.nodes.items(.tag);
if (decl.value == null) {
switch (tags[decl.node_idx]) {
.global_var_decl,
.local_var_decl,
.aligned_var_decl,
.simple_var_decl,
=> {
const var_decl = ast.varDecl(tree, decl.node_idx).?;
if (var_decl.ast.init_node == 0)
return error.CriticalAstFailure;
var value = try (try interpreter.interpret(var_decl.ast.init_node, decl.scope, .{})).getValue();
if (var_decl.ast.type_node != 0) {
var type_val = try (try interpreter.interpret(var_decl.ast.type_node, decl.scope, .{})).getValue();
const type_type = try interpreter.ip.get(interpreter.allocator, IPKey{ .simple = .type });
if (type_val.ty != type_type) {
try interpreter.recordError(
decl.node_idx,
"expected_type",
std.fmt.allocPrint(interpreter.allocator, "expected type 'type', found '{}'", .{type_val.ty.fmtType(&interpreter.ip)}) catch return error.CriticalAstFailure,
);
return error.InvalidCast;
}
value = try interpreter.cast(var_decl.ast.type_node, type_val.value_data.type, value);
}
decl.value = value;
},
else => @panic("No other case supported for lazy declaration evaluation"),
}
}
return decl.value.?;
}
pub fn isConstant(declaration: Declaration) bool {
const tree = declaration.scope.interpreter.getHandle().tree;
return switch (tree.nodes.items(.tag)[declaration.node_idx]) {
.global_var_decl,
.local_var_decl,
.aligned_var_decl,
.simple_var_decl,
=> {
return tree.tokenSlice(ast.varDecl(tree, declaration.node_idx).?.ast.mut_token).len != 3;
},
else => false,
};
}
};
// pub const Comptimeness = enum { @"comptime", runtime };
pub const Scope = struct {
@ -217,21 +130,6 @@ pub const Scope = struct {
}
};
pub fn newScope(
interpreter: *ComptimeInterpreter,
maybe_parent: ?Scope,
node_idx: Ast.Node.Index,
) std.mem.Allocator.Error!*Scope {
var ls = try interpreter.allocator.create(Scope);
if (maybe_parent) |parent| try parent.child_scopes.append(interpreter.allocator, ls);
ls.* = .{
.interpreter = interpreter,
.parent = maybe_parent,
.node_idx = node_idx,
};
return ls;
}
pub const InterpretResult = union(enum) {
@"break": ?[]const u8,
break_with_value: struct {
@ -332,7 +230,7 @@ pub const InterpretError = std.mem.Allocator.Error || std.fmt.ParseIntError || s
pub fn interpret(
interpreter: *ComptimeInterpreter,
node_idx: Ast.Node.Index,
scope: ?Scope,
scope: u32,
options: InterpretOptions,
) InterpretError!InterpretResult {
const tree = interpreter.getHandle().tree;
@ -358,12 +256,13 @@ pub fn interpret(
=> {
const type_type = try interpreter.ip.get(interpreter.allocator, IPKey{ .simple = .type });
var container_scope = Scope{
try interpreter.scopes.append(interpreter.allocator, .{
.interpreter = interpreter,
.parent = if (scope) |sc| sc.parent else 0,
.parent = scope,
.node_idx = node_idx,
.namespace = IPIndex.none, // declarations have not been resolved yet
};
});
const container_scope = @intCast(u32, interpreter.scopes.len - 1);
var fields = std.StringArrayHashMapUnmanaged(InternPool.Struct.Field){};
defer fields.deinit(interpreter.allocator);
@ -469,12 +368,13 @@ pub fn interpret(
.block_two,
.block_two_semicolon,
=> {
var block_scope = Scope{
try interpreter.scopes.append(interpreter.allocator, .{
.interpreter = interpreter,
.parent = if (scope) |sc| sc.parent else 0,
.parent = scope,
.node_idx = node_idx,
.namespace = IPIndex.none,
};
});
const block_scope = @intCast(u32, interpreter.scopes.len - 1);
var buffer: [2]Ast.Node.Index = undefined;
const statements = ast.blockStatements(tree, node_idx, &buffer).?;
@ -483,7 +383,7 @@ pub fn interpret(
const ret = try interpreter.interpret(idx, block_scope, options);
switch (ret) {
.@"break" => |lllll| {
const maybe_block_label_string = if (scope.?.getLabel()) |i| tree.tokenSlice(i) else null;
const maybe_block_label_string = if (interpreter.scopes.get(scope).getLabel()) |i| tree.tokenSlice(i) else null;
if (lllll) |l| {
if (maybe_block_label_string) |ls| {
if (std.mem.eql(u8, l, ls)) {
@ -495,7 +395,7 @@ pub fn interpret(
}
},
.break_with_value => |bwv| {
const maybe_block_label_string = if (scope.?.getLabel()) |i| tree.tokenSlice(i) else null;
const maybe_block_label_string = if (interpreter.scopes.get(scope).getLabel()) |i| tree.tokenSlice(i) else null;
if (bwv.label) |l| {
if (maybe_block_label_string) |ls| {
@ -569,7 +469,8 @@ pub fn interpret(
// TODO: Floats
// Logic to find identifiers in accessible scopes
const decl = interpreter.huntItDown(scope.?.namespace, value, options) catch |err| {
const namespace = interpreter.scopes.items(.namespace)[scope];
const decl = interpreter.huntItDown(namespace, value, options) catch |err| {
if (err == error.IdentifierNotFound) try interpreter.recordError(
node_idx,
"undeclared_identifier",
@ -710,13 +611,13 @@ pub fn interpret(
// TODO: Actually consider operators
if (std.mem.eql(u8, tree.getNodeSource(data[node_idx].lhs), "_")) {
_ = try interpreter.interpret(data[node_idx].rhs, scope.?, options);
_ = try interpreter.interpret(data[node_idx].rhs, scope, options);
return InterpretResult{ .nothing = {} };
}
var ir = try interpreter.interpret(data[node_idx].lhs, scope, options);
var to_value = try ir.getValue();
var from_value = (try (try interpreter.interpret(data[node_idx].rhs, scope.?, options)).getValue());
var from_value = (try (try interpreter.interpret(data[node_idx].rhs, scope, options)).getValue());
_ = try interpreter.cast(undefined, to_value.ty, from_value.ty);
@ -756,7 +657,7 @@ pub fn interpret(
try writer.writeAll("indeterminate");
continue;
};
try writer.print("@as({s}, {s})", .{ value.ty.fmtType(&interpreter.ip), value.val.fmtValue(value.ty, &interpreter.ip) });
try writer.print("@as({}, {})", .{ value.ty.fmtType(&interpreter.ip), value.val.fmtValue(value.ty, &interpreter.ip) });
if (index != params.len - 1)
try writer.writeAll(", ");
}
@ -801,12 +702,14 @@ pub fn interpret(
var handle = interpreter.document_store.getOrLoadHandle(import_uri) orelse return error.ImportFailure;
try interpreter.document_store.ensureInterpreterExists(handle.uri);
return InterpretResult{ .value = Value{
.interpreter = interpreter,
.node_idx = node_idx,
.ty = try interpreter.ip.get(interpreter.allocator, IPKey{ .simple = .type }),
.val = try interpreter.ip.get(interpreter.allocator, IPKey{ .type_value = undefined }), // TODO
} };
return InterpretResult{
.value = Value{
.interpreter = interpreter,
.node_idx = node_idx,
.ty = try interpreter.ip.get(interpreter.allocator, IPKey{ .simple = .type }),
.val = try interpreter.ip.get(interpreter.allocator, IPKey{ .type_value = undefined }), // TODO
},
};
}
if (std.mem.eql(u8, call_name, "@TypeOf")) {
@ -837,9 +740,9 @@ pub fn interpret(
const name = interpreter.ip.indexToKey(field_name.val).bytes.data; // TODO add checks
const has_decl = for (namespace.decls) |decl|{
const has_decl = for (namespace.decls) |decl| {
const decl_name = interpreter.ip.indexToKey(decl).declaration.name;
if(std.mem.eql(u8, decl_name, name)) break true;
if (std.mem.eql(u8, decl_name, name)) break true;
} else false;
return InterpretResult{ .value = Value{
@ -989,10 +892,10 @@ pub fn interpret(
try args.append(interpreter.allocator, try (try interpreter.interpret(param, scope, .{})).getValue());
}
const func_id_result = try interpreter.interpret(call_full.ast.fn_expr, interpreter.root_type.?.getTypeInfo().getScopeOfType().?, .{});
const func_id_result = try interpreter.interpret(call_full.ast.fn_expr, scope, .{});
const func_id_val = try func_id_result.getValue();
const call_res = try interpreter.call(interpreter.root_type.?.getTypeInfo().getScopeOfType().?, func_id_val.node_idx, args.items, options);
const call_res = try interpreter.call(scope, func_id_val.node_idx, args.items, options);
// defer call_res.scope.deinit();
// TODO: Figure out call result memory model; this is actually fine because newScope
// makes this a child of the decl scope which is freed on refresh... in theory
@ -1077,7 +980,7 @@ pub fn interpret(
}
pub const CallResult = struct {
scope: *Scope,
scope: u32,
result: union(enum) {
value: Value,
nothing,
@ -1086,7 +989,7 @@ pub const CallResult = struct {
pub fn call(
interpreter: *ComptimeInterpreter,
scope: ?Scope,
scope: u32,
func_node_idx: Ast.Node.Index,
arguments: []const Value,
options: InterpretOptions,
@ -1101,9 +1004,15 @@ pub fn call(
if (tags[func_node_idx] != .fn_decl) return error.CriticalAstFailure;
// TODO: Make argument scope to evaluate arguments in
var fn_scope = try interpreter.newScope(scope, func_node_idx);
const type_type = try interpreter.ip.get(interpreter.allocator, IPKey{ .simple = .type });
try interpreter.scopes.append(interpreter.allocator, Scope{
.interpreter = interpreter,
.parent = scope,
.node_idx = func_node_idx,
.namespace = IPIndex.none,
});
const fn_scope = @intCast(u32, interpreter.scopes.len - 1);
const type_type = try interpreter.ip.get(interpreter.allocator, IPKey{ .simple = .type });
var buf: [1]Ast.Node.Index = undefined;
var proto = ast.fnProto(tree, func_node_idx, &buf).?;
@ -1122,13 +1031,18 @@ pub fn call(
return error.InvalidCast;
}
if (param.name_token) |nt| {
const decl = Declaration{
.scope = fn_scope,
.node_idx = param.type_expr,
.name = tree.tokenSlice(nt),
.value = try interpreter.cast(arguments[arg_index].node_idx, tex.val, arguments[arg_index]),
};
try fn_scope.declarations.put(interpreter.allocator, tree.tokenSlice(nt), decl);
_ = nt;
// const decl = InternPool.Decl{
// .name = tree.tokenSlice(nt),
// .ty = tex.val,
// .val = try interpreter.cast(arguments[arg_index].node_idx, tex.val, arguments[arg_index].val),
// .alignment = 0, // TODO
// .address_space = .generic, // TODO
// .is_pub = true, // TODO
// .is_exported = false, // TODO
// };
// TODO
// try fn_scope.declarations.put(interpreter.allocator, tree.tokenSlice(nt), decl);
arg_index += 1;
}
}

View File

@ -949,6 +949,6 @@ pub fn ensureInterpreterExists(self: *DocumentStore, uri: Uri) !void {
.uri = uri,
};
handle.interpreter = int;
_ = try int.interpret(0, null, .{});
_ = try int.interpret(0, 0, .{});
}
}

View File

@ -255,6 +255,8 @@ pub const Key = union(enum) {
.float_64_value => |f| std.hash.autoHash(&hasher, @bitCast(u64, f)),
.float_80_value => |f| std.hash.autoHash(&hasher, @bitCast(u80, f)),
.float_128_value => |f| std.hash.autoHash(&hasher, @bitCast(u128, f)),
.bytes => |bytes| hasher.update(bytes.data),
inline else => |info| std.hash.autoHash(&hasher, info), // TODO sad stage1 noises :(
}
return @truncate(u32, hasher.final());
@ -303,9 +305,9 @@ pub const Key = union(enum) {
return true;
},
.union_type => |union_info| {
if (union_info.tag_type != b.union_info.tag_type) return false;
if (union_info.layout != b.union_info.layout) return false;
if (union_info.fields.count() != b.union_info.fields.count()) return false;
if (union_info.tag_type != b.union_type.tag_type) return false;
if (union_info.layout != b.union_type.layout) return false;
if (union_info.fields.count() != b.union_type.fields.count()) return false;
@panic("TODO: implement union equality");
},
.tuple_type => |tuple_info| {
@ -331,17 +333,16 @@ pub const Key = union(enum) {
return true;
},
.namespace => |namespace_info| {
if (!std.meta.eql(namespace_info.parent, b.namespace.parent)) return false;
if (namespace_info.ty != b.namespace.ty) return false;
if (namespace_info.parent != b.namespace.parent) return false;
if (namespace_info.decls.len != b.namespace.decls.len) return false;
if (namespace_info.usingnamespaces.len != b.namespace.usingnamespaces.len) return false;
for (namespace_info.decls) |decl, i| {
if (!decl != b.namespace.decls[i]) return false;
if (decl != b.namespace.decls[i]) return false;
}
for (namespace_info.usingnamespaces) |namespace, i| {
if (!namespace != b.namespace.usingnamespaces[i]) return false;
if (namespace != b.namespace.usingnamespaces[i]) return false;
}
return false;
},
@ -431,37 +432,71 @@ pub const Key = union(enum) {
.bool_false,
=> unreachable,
},
.int_type => .Int,
.pointer_type => .Pointer,
.array_type => .Array,
.struct_type => .Struct,
.optional_type => .Optional,
.error_union_type => .ErrorUnion,
.error_set_type => .ErrorSet,
.enum_type => .Enum,
.function_type => .Fn,
.union_type => .Union,
.tuple_type => .Struct, // TODO this correct?
.vector_type => .Vector,
.declaration,
.namespace,
=> unreachable,
.int_u64_value,
.int_i64_value,
.int_big_value,
.float_16_value,
.float_32_value,
.float_64_value,
.float_80_value,
.float_128_value,
.type_value,
=> unreachable,
.bytes,
.one_pointer,
=> unreachable,
};
}
/// Asserts the type is an integer, enum, error set, packed struct, or vector of one of them.
pub fn intInfo(ty: Key, target: std.Target, ip: InternPool) Int {
pub fn intInfo(ty: Key, target: std.Target, ip: *const InternPool) Int {
var key: Key = ty;
while (true) switch (key) {
.simple => |simple| switch (simple) {
.usize => return .{ .signdness = .signed, .bits = target.cpu.arch.ptrBitWidth() },
.isize => return .{ .signdness = .unsigned, .bits = target.cpu.arch.ptrBitWidth() },
.usize => return .{ .signedness = .signed, .bits = target.cpu.arch.ptrBitWidth() },
.isize => return .{ .signedness = .unsigned, .bits = target.cpu.arch.ptrBitWidth() },
// TODO correctly resolve size based on `target`
.c_short => return .{ .signdness = .signed, .bits = @bitSizeOf(c_short) },
.c_ushort => return .{ .signdness = .unsigned, .bits = @bitSizeOf(c_ushort) },
.c_int => return .{ .signdness = .signed, .bits = @bitSizeOf(c_int) },
.c_uint => return .{ .signdness = .unsigned, .bits = @bitSizeOf(c_uint) },
.c_long => return .{ .signdness = .signed, .bits = @bitSizeOf(c_long) },
.c_ulong => return .{ .signdness = .unsigned, .bits = @bitSizeOf(c_ulong) },
.c_longlong => return .{ .signdness = .signed, .bits = @bitSizeOf(c_longlong) },
.c_ulonglong => return .{ .signdness = .unsigned, .bits = @bitSizeOf(c_ulonglong) },
.c_longdouble => return .{ .signdness = .signed, .bits = @bitSizeOf(c_longdouble) },
.c_short => return .{ .signedness = .signed, .bits = @bitSizeOf(c_short) },
.c_ushort => return .{ .signedness = .unsigned, .bits = @bitSizeOf(c_ushort) },
.c_int => return .{ .signedness = .signed, .bits = @bitSizeOf(c_int) },
.c_uint => return .{ .signedness = .unsigned, .bits = @bitSizeOf(c_uint) },
.c_long => return .{ .signedness = .signed, .bits = @bitSizeOf(c_long) },
.c_ulong => return .{ .signedness = .unsigned, .bits = @bitSizeOf(c_ulong) },
.c_longlong => return .{ .signedness = .signed, .bits = @bitSizeOf(c_longlong) },
.c_ulonglong => return .{ .signedness = .unsigned, .bits = @bitSizeOf(c_ulonglong) },
.c_longdouble => return .{ .signedness = .signed, .bits = @bitSizeOf(c_longdouble) },
// TODO revisit this when error sets support custom int types (comment taken from zig codebase)
.anyerror => return .{ .signedness = .unsigned, .bits = 16 },
else => unreachable,
},
.int_type => |int_info| return int_info,
.enum_type => @panic("TODO"),
.struct_type => |struct_info| {
std.debug.assert(struct_info.layout == .Packed);
key = struct_info.backing_int_ty;
key = ip.indexToKey(struct_info.backing_int_ty);
},
// TODO revisit this when error sets support custom int types (comment taken from zig codebase)
.error_set_type => return .{ .signedness = .unsigned, .bits = 16 },
@ -469,7 +504,6 @@ pub const Key = union(enum) {
std.debug.assert(vector_info.len == 1);
key = ip.indexToKey(vector_info.child);
},
else => unreachable,
};
}
@ -511,13 +545,20 @@ pub const Key = union(enum) {
};
}
pub fn isConstPtr(ty: Key) bool {
return switch (ty) {
.pointer_type => |pointer_info| pointer_info.is_const,
else => false,
};
}
pub fn isSlice(ty: Key) bool {
return switch (ty) {
.pointer_type => |pointer_info| pointer_info.size == .Slice,
else => false,
};
}
pub fn getNamespace(ty: Key) ?Index {
return switch (ty) {
.struct_type => |struct_info| struct_info.namespace,
@ -1030,7 +1071,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
.type => .{ .type_value = @intToEnum(Index, data) },
.bytes => unreachable, // TODO
.one_pointer => .{.one_pointer = @intToEnum(Index, data)},
.one_pointer => .{ .one_pointer = @intToEnum(Index, data) },
else => @panic("TODO"),
};
}
@ -1068,7 +1109,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.float_32_value => |float_val| .{ .tag = .float_f32, .data = @bitCast(u32, float_val) },
.type_value => |ty| .{ .tag = .type, .data = @enumToInt(ty) },
.bytes => unreachable, // TODO
.one_pointer => |val| .{.tag = .one_pointer, .data = @enumToInt(val)},
.one_pointer => |val| .{ .tag = .one_pointer, .data = @enumToInt(val) },
inline else => |data| .{ .tag = key.tag(), .data = try ip.addExtra(gpa, data) }, // TODO sad stage1 noises :(
};
try ip.items.append(gpa, item);
@ -1095,26 +1136,31 @@ fn extraData(ip: InternPool, comptime T: type, index: usize) T {
// ---------------------------------------------
pub fn cast(ip: *InternPool, gpa: Allocator, destination_ty: Index, source_ty: Index, target: std.Target) Allocator.Error!Index {
return resolvePeerTypes(ip, gpa, &.{destination_ty, source_ty}, target);
return resolvePeerTypes(ip, gpa, &.{ destination_ty, source_ty }, target);
}
pub fn resolvePeerTypes(ip: *InternPool, gpa: Allocator, types: []const Index, target: std.Target) Allocator.Error!Index {
switch (types.len) {
0 => return Key{ .simple = .noreturn },
1 => types[0],
0 => return try ip.get(gpa, .{ .simple = .noreturn }),
1 => return types[0],
else => {},
}
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
defer arena_allocator.deinit();
var arena = arena_allocator.allocator();
var chosen = types[0];
var any_are_null = false;
var seen_const = false;
var convert_to_slice = false;
var chosen_i: usize = 0;
for (types[1..]) |candidate, candidate_i| {
if (candidate == chosen) continue;
const candidate_key: Key = ip.indexToKey(candidate);
const chosen_key = ip.indexToKey(chosen);
if (candidate_key == chosen_key) continue;
switch (candidate_key) {
.simple => |candidate_simple| switch (candidate_simple) {
// TODO usize, isize
@ -1133,6 +1179,7 @@ pub fn resolvePeerTypes(ip: *InternPool, gpa: Allocator, types: []const Index, t
},
else => {},
},
else => {},
},
.noreturn, .undefined_type => continue,
@ -1148,6 +1195,7 @@ pub fn resolvePeerTypes(ip: *InternPool, gpa: Allocator, types: []const Index, t
.usize, .isize => continue,
.comptime_int => unreachable,
.comptime_float => continue,
else => {},
},
.int_type => continue,
.pointer_type => |chosen_info| if (chosen_info.size == .C) continue,
@ -1161,6 +1209,7 @@ pub fn resolvePeerTypes(ip: *InternPool, gpa: Allocator, types: []const Index, t
chosen_i = candidate_i + 1;
continue;
},
else => {},
},
else => {},
},
@ -1242,13 +1291,13 @@ pub fn resolvePeerTypes(ip: *InternPool, gpa: Allocator, types: []const Index, t
const chosen_elem_ty = chosen_elem_info.array_type.child;
const cand_elem_ty = candidate_elem_info.array_type.child;
const chosen_ok = .ok == try ip.coerceInMemoryAllowed(gpa, chosen_elem_ty, cand_elem_ty, chosen_info.mutable, target);
const chosen_ok = .ok == try ip.coerceInMemoryAllowed(gpa, chosen_elem_ty, cand_elem_ty, !chosen_info.is_const, target);
if (chosen_ok) {
convert_to_slice = true;
continue;
}
const cand_ok = .ok == try ip.coerceInMemoryAllowed(gpa, cand_elem_ty, chosen_elem_ty, candidate_info.mutable, target);
const cand_ok = .ok == try ip.coerceInMemoryAllowed(gpa, cand_elem_ty, chosen_elem_ty, !candidate_info.is_const, target);
if (cand_ok) {
convert_to_slice = true;
chosen = candidate;
@ -1268,8 +1317,8 @@ pub fn resolvePeerTypes(ip: *InternPool, gpa: Allocator, types: []const Index, t
// the one we will keep. If they're both OK then we keep the
// C pointer since it matches both single and many pointers.
if (candidate_info.size == .C or chosen_info.size == .C) {
const cand_ok = .ok == try ip.coerceInMemoryAllowed(candidate_info.elem_type, chosen_info.elem_type, candidate_info.mutable, target);
const chosen_ok = .ok == try ip.coerceInMemoryAllowed(chosen_info.elem_type, candidate_info.elem_type, chosen_info.mutable, target);
const cand_ok = .ok == try ip.coerceInMemoryAllowed(arena, candidate_info.elem_type, chosen_info.elem_type, !candidate_info.is_const, target);
const chosen_ok = .ok == try ip.coerceInMemoryAllowed(arena, chosen_info.elem_type, candidate_info.elem_type, !chosen_info.is_const, target);
if (cand_ok) {
if (!chosen_ok or chosen_info.size != .C) {
@ -1327,14 +1376,16 @@ pub fn resolvePeerTypes(ip: *InternPool, gpa: Allocator, types: []const Index, t
}
}
},
.function_type => {
if (candidate_info.is_const and
ip.indexToKey(candidate_info.elem_type) == .function_type and
.ok == try ip.coerceInMemoryAllowedFns(chosen, candidate_info.pointee_type, target))
{
chosen = candidate;
chosen_i = candidate_i + 1;
continue;
.function_type => |chosen_info| {
if (candidate_info.is_const) {
const candidate_elem_key = ip.indexToKey(candidate_info.elem_type);
if (candidate_elem_key == .function_type and
.ok == try ip.coerceInMemoryAllowedFns(arena, chosen_info, candidate_elem_key.function_type, target))
{
chosen = candidate;
chosen_i = candidate_i + 1;
continue;
}
}
},
else => {},
@ -1349,8 +1400,8 @@ pub fn resolvePeerTypes(ip: *InternPool, gpa: Allocator, types: []const Index, t
else => false,
};
if ((try ip.coerceInMemoryAllowed(chosen, candidate_info.payload_type, false, target)) == .ok) {
seen_const = seen_const or candidate_info.payload_type.isConstPtr();
if ((try ip.coerceInMemoryAllowed(arena, chosen, candidate_info.payload_type, false, target)) == .ok) {
seen_const = seen_const or ip.indexToKey(candidate_info.payload_type).isConstPtr();
any_are_null = true;
continue;
}
@ -1374,44 +1425,42 @@ pub fn resolvePeerTypes(ip: *InternPool, gpa: Allocator, types: []const Index, t
switch (chosen_key) {
.simple => |simple| switch (simple) {
.noreturn, .undefined_type => {
.noreturn,
.undefined_type,
=> {
chosen = candidate;
chosen_i = candidate_i + 1;
continue;
},
}
.NoReturn,
.Undefined => {
chosen = candidate;
chosen_i = candidate_i + 1;
continue;
.null_type => {
any_are_null = true;
chosen = candidate;
chosen_i = candidate_i + 1;
continue;
},
else => {},
},
.Null => {
any_are_null = true;
chosen = candidate;
chosen_i = candidate_i + 1;
continue;
},
.Optional => {
if ((try ip.coerceInMemoryAllowed(chosen_key.optional_type.payload_type, candidate, false, target)) == .ok) {
.optional_type => |chosen_info| {
if ((try ip.coerceInMemoryAllowed(arena, chosen_info.payload_type, candidate, false, target)) == .ok) {
continue;
}
if ((try ip.coerceInMemoryAllowed(candidate, chosen_key.optional_type.payload_type, false, target)) == .ok) {
if ((try ip.coerceInMemoryAllowed(arena, candidate, chosen_info.payload_type, false, target)) == .ok) {
any_are_null = true;
chosen = candidate;
chosen_i = candidate_i + 1;
continue;
}
},
.ErrorUnion => {
const payload_ty = chosen_key.error_union_type.payload_type;
if ((try ip.coerceInMemoryAllowed(payload_ty, candidate, false, target)) == .ok) {
.error_union_type => |chosen_info| {
if ((try ip.coerceInMemoryAllowed(arena, chosen_info.payload_type, candidate, false, target)) == .ok) {
continue;
}
},
else => {},
}
}
@panic("TODO");
}
const InMemoryCoercionResult = union(enum) {
@ -1542,7 +1591,7 @@ fn coerceInMemoryAllowed(
src_ty: Index,
dest_is_mut: bool,
target: std.Target,
) !InMemoryCoercionResult {
) error{OutOfMemory}!InMemoryCoercionResult {
if (dest_ty == src_ty) return .ok;
const dest_key = ip.indexToKey(dest_ty);
@ -1576,7 +1625,7 @@ fn coerceInMemoryAllowed(
if (dest_tag == .Float and src_tag == .Float and
// this is an optimization because only a long double can have the same size as a other Float
// SAFETY: every Float is a Simple
dest_key.simple == .c_longdouble or src_tag.simple == .c_longdouble)
dest_key.simple == .c_longdouble or src_key.simple == .c_longdouble)
{
const dest_bits = dest_key.floatBits(target);
const src_bits = src_key.floatBits(target);
@ -1587,24 +1636,26 @@ fn coerceInMemoryAllowed(
const maybe_dest_ptr_ty = try ip.typePtrOrOptionalPtrTy(dest_ty);
const maybe_src_ptr_ty = try ip.typePtrOrOptionalPtrTy(src_ty);
if (maybe_dest_ptr_ty != Index.none and maybe_src_ptr_ty != Index.none) {
return try ip.coerceInMemoryAllowedPtrs(dest_ty, src_ty, maybe_dest_ptr_ty, maybe_src_ptr_ty, dest_is_mut, target);
@panic("TODO: implement coerceInMemoryAllowedPtrs");
// return try ip.coerceInMemoryAllowedPtrs(dest_ty, src_ty, maybe_dest_ptr_ty, maybe_src_ptr_ty, dest_is_mut, target);
}
// Slices
if (dest_key.isSlice() and src_key.isSlice()) {
return try ip.coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target);
@panic("TODO: implement coerceInMemoryAllowedPtrs");
// return try ip.coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target);
}
// Functions
if (dest_tag == .Fn and src_tag == .Fn) {
return try ip.coerceInMemoryAllowedFns(dest_ty, src_ty, target);
return try ip.coerceInMemoryAllowedFns(arena, dest_key.function_type, src_key.function_type, target);
}
// Error Unions
if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) {
const dest_payload = dest_key.error_union_type.payload_type;
const src_payload = src_key.error_union_type.payload_type;
const child = try ip.coerceInMemoryAllowed(dest_payload, src_payload, dest_is_mut, target);
const child = try ip.coerceInMemoryAllowed(arena, dest_payload, src_payload, dest_is_mut, target);
if (child != .ok) {
return InMemoryCoercionResult{ .error_union_payload = .{
.child = try child.dupe(arena),
@ -1612,7 +1663,9 @@ fn coerceInMemoryAllowed(
.wanted = dest_payload,
} };
}
return try ip.coerceInMemoryAllowed(dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target);
const dest_set = dest_key.error_union_type.error_set_type;
const src_set = src_key.error_union_type.error_set_type;
return try ip.coerceInMemoryAllowed(arena, dest_set, src_set, dest_is_mut, target);
}
// Error Sets
@ -1623,8 +1676,8 @@ fn coerceInMemoryAllowed(
// Arrays
if (dest_tag == .Array and src_tag == .Array) {
const dest_info = dest_key.array_type.len;
const src_info = src_key.array_type.len;
const dest_info = dest_key.array_type;
const src_info = src_key.array_type;
if (dest_info.len != src_info.len) {
return InMemoryCoercionResult{ .array_len = .{
.actual = src_info.len,
@ -1632,24 +1685,24 @@ fn coerceInMemoryAllowed(
} };
}
const child = try ip.coerceInMemoryAllowed(dest_key.array_type.child, src_key.array_type.child, dest_is_mut, target);
const child = try ip.coerceInMemoryAllowed(arena, dest_info.child, src_info.child, dest_is_mut, target);
if (child != .ok) {
return InMemoryCoercionResult{ .array_elem = .{
.child = try child.dupe(arena),
.actual = src_key.array_type.child,
.wanted = dest_key.array_type.child,
.actual = src_info.child,
.wanted = dest_info.child,
} };
}
const ok_sent = dest_key.array_type.sentinel == Index.none or
(src_key.array_type.sentinel != Index.none and
dest_key.array_type.sentinel == src_key.array_type.sentinel // is this enough for a value equality check?
const ok_sent = dest_info.sentinel == Index.none or
(src_info.sentinel != Index.none and
dest_info.sentinel == src_info.sentinel // is this enough for a value equality check?
);
if (!ok_sent) {
return InMemoryCoercionResult{ .array_sentinel = .{
.actual = src_info.sentinel,
.wanted = dest_info.sentinel,
.ty = dest_key.array_type.child,
.ty = dest_info.child,
} };
}
return .ok;
@ -1669,7 +1722,7 @@ fn coerceInMemoryAllowed(
const dest_elem_ty = dest_key.vector_type.child;
const src_elem_ty = src_key.vector_type.child;
const child = try ip.coerceInMemoryAllowed(dest_elem_ty, src_elem_ty, dest_is_mut, target);
const child = try ip.coerceInMemoryAllowed(arena, dest_elem_ty, src_elem_ty, dest_is_mut, target);
if (child != .ok) {
return InMemoryCoercionResult{ .vector_elem = .{
.child = try child.dupe(arena),
@ -1693,7 +1746,7 @@ fn coerceInMemoryAllowed(
const dest_child_type = dest_key.optional_type.payload_type;
const src_child_type = src_key.optional_type.payload_type;
const child = try ip.coerceInMemoryAllowed(dest_child_type, src_child_type, dest_is_mut, target);
const child = try ip.coerceInMemoryAllowed(arena, dest_child_type, src_child_type, dest_is_mut, target);
if (child != .ok) {
return InMemoryCoercionResult{ .optional_child = .{
.child = try child.dupe(arena),
@ -1865,13 +1918,10 @@ fn coerceInMemoryAllowed(
fn coerceInMemoryAllowedFns(
ip: *InternPool,
arena: std.mem.Allocator,
dest_ty: Index,
src_ty: Index,
dest_info: Fn,
src_info: Fn,
target: std.Target,
) !InMemoryCoercionResult {
const dest_info = dest_ty.fnInfo();
const src_info = src_ty.fnInfo();
if (dest_info.is_var_args != src_info.is_var_args) {
return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args };
}
@ -1880,15 +1930,18 @@ fn coerceInMemoryAllowedFns(
return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
}
if (dest_info.cc != src_info.cc) {
if (dest_info.calling_convention != src_info.calling_convention) {
return InMemoryCoercionResult{ .fn_cc = .{
.actual = src_info.cc,
.wanted = dest_info.cc,
.actual = src_info.calling_convention,
.wanted = dest_info.calling_convention,
} };
}
if (!src_info.return_type.isNoReturn()) {
const rt = try ip.coerceInMemoryAllowed(dest_info.return_type, src_info.return_type, false, target);
const return_type_key = ip.indexToKey(src_info.return_type);
const is_noreturn = return_type_key == .simple and return_type_key.simple == .noreturn;
if (!is_noreturn) {
const rt = try ip.coerceInMemoryAllowed(arena, dest_info.return_type, src_info.return_type, false, target);
if (rt != .ok) {
return InMemoryCoercionResult{ .fn_return_type = .{
.child = try rt.dupe(arena),
@ -1898,41 +1951,43 @@ fn coerceInMemoryAllowedFns(
}
}
if (dest_info.param_types.len != src_info.param_types.len) {
if (dest_info.args.len != src_info.args.len) {
return InMemoryCoercionResult{ .fn_param_count = .{
.actual = src_info.param_types.len,
.wanted = dest_info.param_types.len,
.actual = src_info.args.len,
.wanted = dest_info.args.len,
} };
}
if (dest_info.noalias_bits != src_info.noalias_bits) {
return InMemoryCoercionResult{ .fn_param_noalias = .{
.actual = src_info.noalias_bits,
.wanted = dest_info.noalias_bits,
} };
}
// TODO
for (dest_info.param_types) |dest_param_ty, i| {
const src_param_ty = src_info.param_types[i];
// if (dest_info.noalias_bits != src_info.noalias_bits) {
// return InMemoryCoercionResult{ .fn_param_noalias = .{
// .actual = src_info.noalias_bits,
// .wanted = dest_info.noalias_bits,
// } };
// }
if (dest_info.comptime_params[i] != src_info.comptime_params[i]) {
return InMemoryCoercionResult{ .fn_param_comptime = .{
.index = i,
.wanted = dest_info.comptime_params[i],
} };
}
// for (dest_info.param_types) |dest_param_ty, i| {
// const src_param_ty = src_info.param_types[i];
// Note: Cast direction is reversed here.
const param = try ip.coerceInMemoryAllowed(src_param_ty, dest_param_ty, false, target);
if (param != .ok) {
return InMemoryCoercionResult{ .fn_param = .{
.child = try param.dupe(arena),
.actual = src_param_ty,
.wanted = dest_param_ty,
.index = i,
} };
}
}
// if (dest_info.comptime_params[i] != src_info.comptime_params[i]) {
// return InMemoryCoercionResult{ .fn_param_comptime = .{
// .index = i,
// .wanted = dest_info.comptime_params[i],
// } };
// }
// // Note: Cast direction is reversed here.
// const param = try ip.coerceInMemoryAllowed(src_param_ty, dest_param_ty, false, target);
// if (param != .ok) {
// return InMemoryCoercionResult{ .fn_param = .{
// .child = try param.dupe(arena),
// .actual = src_param_ty,
// .wanted = dest_param_ty,
// .index = i,
// } };
// }
// }
return .ok;
}
@ -1943,8 +1998,8 @@ fn coerceInMemoryAllowedFns(
/// a type has zero bits, which can cause a "foo depends on itself" compile error.
/// This logic must be kept in sync with `Type.isPtrLikeOptional`.
fn typePtrOrOptionalPtrTy(
ty: Index,
ip: InternPool,
ty: Index,
) !Index {
const key = ip.indexToKey(ty);
switch (key) {
@ -1960,7 +2015,7 @@ fn typePtrOrOptionalPtrTy(
if (child_key != .pointer_type) return Index.none;
const child_ptr_key = child_key.pointer_type;
switch (child_ptr_key) {
switch (child_ptr_key.size) {
.Slice, .C => return Index.none,
.Many, .One => {
if (child_ptr_key.is_allowzero) return Index.none;

View File

@ -769,15 +769,15 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl
};
var interpreter = handle.interpreter.?;
var root_scope = ComptimeInterpreter.Scope{
try interpreter.scopes.append(interpreter.allocator, .{
.interpreter = interpreter,
.parent = 0,
.node_idx = 0,
.namespace = ComptimeInterpreter.IPIndex.none,
};
.namespace = .none,
});
// TODO: Start from current/nearest-current scope
const result = interpreter.interpret(node, root_scope, .{}) catch |err| {
const result = interpreter.interpret(node, 0, .{}) catch |err| {
log.err("Interpreter error: {s}", .{@errorName(err)});
if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace.*);
@ -794,7 +794,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl
const type_type = try interpreter.ip.get(interpreter.allocator, ComptimeInterpreter.IPKey{ .simple = .type });
if (val.ty != type_type) {
log.err("Not a type: { }", .{val.ty.fmtType(&interpreter.ip)});
log.err("Not a type: {}", .{val.ty.fmtType(&interpreter.ip)});
return null;
}