From 6118686d005544a3ab70258bbec778b72f11e6b6 Mon Sep 17 00:00:00 2001 From: Techatrix <19954306+Techatrix@users.noreply.github.com> Date: Tue, 27 Dec 2022 03:02:07 +0100 Subject: [PATCH] fix remaining compiler errors --- src/ComptimeInterpreter.zig | 188 +++++++---------------- src/DocumentStore.zig | 2 +- src/InternPool.zig | 295 +++++++++++++++++++++--------------- src/analysis.zig | 10 +- 4 files changed, 232 insertions(+), 263 deletions(-) diff --git a/src/ComptimeInterpreter.zig b/src/ComptimeInterpreter.zig index 7c33fe9..a9c9c2b 100644 --- a/src/ComptimeInterpreter.zig +++ b/src/ComptimeInterpreter.zig @@ -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; } } diff --git a/src/DocumentStore.zig b/src/DocumentStore.zig index 8276b08..f5cd582 100644 --- a/src/DocumentStore.zig +++ b/src/DocumentStore.zig @@ -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, .{}); } } diff --git a/src/InternPool.zig b/src/InternPool.zig index 465959b..9de7018 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -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; diff --git a/src/analysis.zig b/src/analysis.zig index 4de63b7..3774b03 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -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; }