Merge pull request #149 from birth-software/actually-implement-polymorphism-on-functions

Actually implement polymorphism in functions
This commit is contained in:
David 2024-04-17 21:18:55 -06:00 committed by GitHub
commit e2008be871
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 171 additions and 80 deletions

View File

@ -3270,40 +3270,13 @@ fn getTypeHomogeneousAggregate(ty: *Type, unit: *Unit) ?HomogeneousAggregate {
const _usize: Type.Index = .u64; const _usize: Type.Index = .u64;
const _ssize: Type.Index = .s64; const _ssize: Type.Index = .s64;
pub const Type = union(enum) { fn serialize_comptime_parameters(unit: *Unit, context: *const Context, original_declaration: *Debug.Declaration, parameters: []const V.Comptime) !u32 {
void,
noreturn,
type,
any,
@"struct": Struct.Index,
function: Function.Prototype.Index,
integer: Type.Integer,
pointer: Type.Pointer,
slice: Type.Slice,
array: Type.Array,
polymorphic: Type.Polymorphic,
pub const @"usize" = _usize;
pub const ssize = _ssize;
pub const Polymorphic = struct {
parameters: []const Token.Index,
instantiations: MyHashMap(u32, *Debug.Declaration.Global) = .{},
node: Node.Index,
pub fn get_instantiation(polymorphic: *Polymorphic, types: []const V.Comptime) ?*Debug.Declaration.Global {
const parameter_hash = hash(types);
const result = polymorphic.instantiations.get(parameter_hash);
return result;
}
pub fn add_instantiation(polymorphic: *Polymorphic, unit: *Unit, context: *const Context, parameters: []const V.Comptime, original_declaration: *Debug.Declaration.Global, type_index: Type.Index) !void {
var name = UnpinnedArray(u8){}; var name = UnpinnedArray(u8){};
const original_name = unit.getIdentifier(original_declaration.declaration.name); const original_name = unit.getIdentifier(original_declaration.name);
try name.append_slice(context.my_allocator, original_name); try name.append_slice(context.my_allocator, original_name);
assert(parameters.len > 0);
try name.append(context.my_allocator, '('); try name.append(context.my_allocator, '(');
if (parameters.len > 0) {
for (parameters) |parameter| { for (parameters) |parameter| {
switch (parameter) { switch (parameter) {
.type => |parameter_type_index| if (unit.type_declarations.get(parameter_type_index)) |foo| { .type => |parameter_type_index| if (unit.type_declarations.get(parameter_type_index)) |foo| {
@ -3335,9 +3308,41 @@ pub const Type = union(enum) {
name.length -= 2; name.length -= 2;
name.pointer[name.length] = ')'; name.pointer[name.length] = ')';
name.length += 1; name.length += 1;
}
const name_hash = try unit.processIdentifier(context, name.slice()); const name_hash = try unit.processIdentifier(context, name.slice());
return name_hash;
}
pub const Type = union(enum) {
void,
noreturn,
type,
any,
@"struct": Struct.Index,
function: Function.Prototype.Index,
integer: Type.Integer,
pointer: Type.Pointer,
slice: Type.Slice,
array: Type.Array,
polymorphic: Type.Polymorphic,
polymorphic_function: void,
pub const @"usize" = _usize;
pub const ssize = _ssize;
pub const Polymorphic = struct {
parameters: []const Token.Index,
instantiations: MyHashMap(u32, *Debug.Declaration.Global) = .{},
node: Node.Index,
pub fn get_instantiation(polymorphic: *Polymorphic, types: []const V.Comptime) ?*Debug.Declaration.Global {
const parameter_hash = hash(types);
const result = polymorphic.instantiations.get(parameter_hash);
return result;
}
pub fn add_instantiation(polymorphic: *Polymorphic, unit: *Unit, context: *const Context, parameters: []const V.Comptime, original_declaration: *Debug.Declaration.Global, type_index: Type.Index) !void {
const name_hash = try serialize_comptime_parameters(unit, context, &original_declaration.declaration, parameters);
const new_declaration_index = try unit.global_declarations.append(context.my_allocator, .{ const new_declaration_index = try unit.global_declarations.append(context.my_allocator, .{
.declaration = .{ .declaration = .{
@ -3531,6 +3536,7 @@ pub const Type = union(enum) {
s16, s16,
s32, s32,
s64, s64,
polymorphic_function,
// usize, // usize,
// ssize, // ssize,
@ -3618,6 +3624,7 @@ pub const Type = union(enum) {
.kind = .materialized_int, .kind = .materialized_int,
}, },
}, },
.polymorphic_function = .polymorphic_function,
// .ssize = .{ // .ssize = .{
// .integer = .{ // .integer = .{
// .bit_count = 64, // .bit_count = 64,
@ -3909,7 +3916,6 @@ pub const Function = struct {
body: Debug.Block.Index, body: Debug.Block.Index,
return_pointer: Instruction.Index = .null, return_pointer: Instruction.Index = .null,
alloca_index: u32 = 1, alloca_index: u32 = 1,
has_polymorphic_parameters: bool = false,
pub const List = BlockList(@This(), enum {}); pub const List = BlockList(@This(), enum {});
pub usingnamespace @This().List.Index; pub usingnamespace @This().List.Index;
@ -3926,6 +3932,7 @@ pub const Function = struct {
abi: Prototype.Abi = .{}, abi: Prototype.Abi = .{},
attributes: Attributes = .{}, attributes: Attributes = .{},
calling_convention: CallingConvention = .auto, calling_convention: CallingConvention = .auto,
has_polymorphic_parameters: bool = false,
// comptime_parameter_declarations: []const ComptimeParameterDeclaration = &.{}, // comptime_parameter_declarations: []const ComptimeParameterDeclaration = &.{},
// comptime_parameter_instantiations: []const V.Comptime = &.{}, // comptime_parameter_instantiations: []const V.Comptime = &.{},
// is_member: bool = false, // is_member: bool = false,
@ -4055,10 +4062,49 @@ pub const PolymorphicFunction = struct {
node: Node.Index, node: Node.Index,
is_member_call: bool, is_member_call: bool,
pub fn add_instantiation() void { pub fn get_instantiation(polymorphic_function: *PolymorphicFunction, types: []const V.Comptime) ?*Debug.Declaration.Global {
const param_hash = hash(types);
const result = polymorphic_function.instantiations.get(param_hash);
return result;
} }
fn hash() void { pub fn add_instantiation(polymorphic_function: *PolymorphicFunction, unit: *Unit, context: *const Context, parameters: []const V.Comptime, original_declaration: *Debug.Declaration.Global, function_definition_index: Function.Definition.Index) !*Debug.Declaration.Global {
const name_hash = try serialize_comptime_parameters(unit, context, &original_declaration.declaration, parameters);
if (original_declaration.declaration.type != .null) {
assert(original_declaration.declaration.type == .polymorphic_function);
}
const function_definition = unit.function_definitions.get(function_definition_index);
const type_index = function_definition.type;
const new_declaration_index = try unit.global_declarations.append(context.my_allocator, .{
.declaration = .{
.scope = original_declaration.declaration.scope,
.type = type_index,
.name = name_hash,
.line = original_declaration.declaration.line,
.column = original_declaration.declaration.column,
.mutability = original_declaration.declaration.mutability,
.kind = original_declaration.declaration.kind,
},
.initial_value = .{
.function_definition = function_definition_index,
},
.type_node_index = original_declaration.type_node_index,
.attributes = original_declaration.attributes,
});
const new_declaration = unit.global_declarations.get(new_declaration_index);
const parameter_hash = hash(parameters);
try polymorphic_function.instantiations.put_no_clobber(context.my_allocator, parameter_hash, new_declaration);
return new_declaration;
}
fn hash(parameters: []const V.Comptime) u32 {
const result = data_structures.my_hash(std.mem.sliceAsBytes(parameters));
return result;
} }
}; };
@ -4137,6 +4183,7 @@ pub const V = struct {
.comptime_int => .comptime_int, .comptime_int => .comptime_int,
.constant_struct => |constant_struct| unit.constant_structs.get(constant_struct).type, .constant_struct => |constant_struct| unit.constant_structs.get(constant_struct).type,
.function_declaration => |function_type| function_type, .function_declaration => |function_type| function_type,
.polymorphic_function=> .polymorphic_function,
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
} }
@ -5229,15 +5276,16 @@ pub const Builder = struct {
} }
switch (global_declaration.initial_value) { switch (global_declaration.initial_value) {
.polymorphic_function => |*polymorphic_function| {
assert(polymorphic_function.instantiations.length == 1);
const function_definition_global = polymorphic_function.instantiations.values()[0];
assert(function_definition_global.initial_value == .function_definition);
try unit.code_to_emit.put_no_clobber(context.my_allocator, function_definition_global.initial_value.function_definition, function_definition_global);
return function_definition_global;
},
.function_definition => |function_definition_index| { .function_definition => |function_definition_index| {
// const function_definition = unit.function_definitions.get(function_definition_index);
// if (function_definition.has_polymorphic_parameters) {
// const function_prototype_index = unit.types.get(function_definition.type).function;
// const function_prototype = unit.function_prototypes.get(function_prototype_index);
// assert(function_prototype.comptime_parameter_declarations.len > 0);
// assert(function_prototype.comptime_parameter_instantiations.len > 0);
// unreachable;
// } else {
switch (unit.getNode(declaration_node_index).id) { switch (unit.getNode(declaration_node_index).id) {
.function_definition => try unit.code_to_emit.put_no_clobber(context.my_allocator, function_definition_index, global_declaration), .function_definition => try unit.code_to_emit.put_no_clobber(context.my_allocator, function_definition_index, global_declaration),
else => { else => {
@ -5247,7 +5295,6 @@ pub const Builder = struct {
}; };
}, },
} }
// }
}, },
.function_declaration => |function_type| { .function_declaration => |function_type| {
switch (unit.getNode(declaration_node_index).id) { switch (unit.getNode(declaration_node_index).id) {
@ -5264,8 +5311,9 @@ pub const Builder = struct {
assert(declaration.type == .type); assert(declaration.type == .type);
switch (unit.types.get(type_index).*) { switch (unit.types.get(type_index).*) {
.polymorphic => |*poly| if (new_parameters.len > 0) { .polymorphic => |*poly| if (new_parameters.len > 0) {
const result = poly.get_instantiation(new_parameters) orelse unreachable; if (poly.get_instantiation(new_parameters)) |result| return result else {
return result; unreachable;
}
}, },
else => unit.type_declarations.put(context.my_allocator, type_index, global_declaration) catch { else => unit.type_declarations.put(context.my_allocator, type_index, global_declaration) catch {
assert(unit.type_declarations.get(type_index).? == global_declaration); assert(unit.type_declarations.get(type_index).? == global_declaration);
@ -5279,7 +5327,14 @@ pub const Builder = struct {
}, },
} }
}, },
else => {}, .polymorphic_function => |*polymorphic_function| {
const instantiation_value = try builder.resolveComptimeValue(unit, context, Type.Expect.none, global_declaration.attributes, polymorphic_function.node, global_declaration, .right, new_parameters, maybe_member_value, polymorphic_argument_nodes);
const instantiation_global = instantiation_value.global;
try unit.code_to_emit.put(context.my_allocator, instantiation_global.initial_value.function_definition, instantiation_global);
return instantiation_global;
},
else => {}
} }
inline for (@typeInfo(Debug.Declaration.Global.Attribute).Enum.fields) |attribute_enum_field| { inline for (@typeInfo(Debug.Declaration.Global.Attribute).Enum.fields) |attribute_enum_field| {
@ -6671,7 +6726,7 @@ pub const Builder = struct {
}, },
.function_prototype => block: { .function_prototype => block: {
var b = false; var b = false;
const fp = try builder.resolveFunctionPrototype(unit, context, node_index, .{}, null, &.{}, null, null, &b); const fp = try builder.resolveFunctionPrototype(unit, context, node_index, .{}, null, &.{}, null, null, null, &b, null);
break :block fp; break :block fp;
}, },
.error_union => blk: { .error_union => blk: {
@ -6791,8 +6846,8 @@ pub const Builder = struct {
} }
} }
fn resolveFunctionPrototype(builder: *Builder, unit: *Unit, context: *const Context, node_index: Node.Index, global_attributes: Debug.Declaration.Global.Attributes, member: ?V, polymorphic_argument_nodes: []const Node.Index, maybe_scope: ?*Debug.Scope.Function, comptime_declarations: ?*UnpinnedArray(ComptimeParameterDeclaration), is_member: *bool) !Type.Index { fn resolveFunctionPrototype(builder: *Builder, unit: *Unit, context: *const Context, node_index: Node.Index, global_attributes: Debug.Declaration.Global.Attributes, member: ?V, polymorphic_argument_nodes: []const Node.Index, maybe_scope: ?*Debug.Scope.Function, maybe_comptime_argument_declarations: ?*UnpinnedArray(ComptimeParameterDeclaration), maybe_comptime_argument_instantiations: ?*UnpinnedArray(V.Comptime), is_member: *bool, maybe_global: ?*Debug.Declaration.Global) !Type.Index {
_ = comptime_declarations; // autofix _ = maybe_global; // autofix
const node = unit.getNode(node_index); const node = unit.getNode(node_index);
assert(node.id == .function_prototype); assert(node.id == .function_prototype);
const attribute_and_return_type_node_list = unit.getNodeList(node.right); const attribute_and_return_type_node_list = unit.getNodeList(node.right);
@ -6847,6 +6902,8 @@ pub const Builder = struct {
var argument_types = try UnpinnedArray(Type.Index).initialize_with_capacity(context.my_allocator, @intCast(argument_node_list.len)); var argument_types = try UnpinnedArray(Type.Index).initialize_with_capacity(context.my_allocator, @intCast(argument_node_list.len));
if (polymorphic_argument_nodes.len > 0) { if (polymorphic_argument_nodes.len > 0) {
const comptime_parameter_declarations = maybe_comptime_argument_declarations orelse unreachable;
const comptime_parameter_instantiations = maybe_comptime_argument_instantiations orelse unreachable;
is_member.* = polymorphic_argument_nodes.len + 1 == argument_node_list.len; is_member.* = polymorphic_argument_nodes.len + 1 == argument_node_list.len;
const scope = maybe_scope orelse unreachable; const scope = maybe_scope orelse unreachable;
assert(&scope.scope == builder.current_scope); assert(&scope.scope == builder.current_scope);
@ -6864,9 +6921,6 @@ pub const Builder = struct {
argument_types.append_with_capacity(member_type); argument_types.append_with_capacity(member_type);
} }
var comptime_parameter_declarations = UnpinnedArray(ComptimeParameterDeclaration){};
var comptime_parameter_instantiations = UnpinnedArray(V.Comptime){};
for (argument_node_list[@intFromBool(is_member.*)..], polymorphic_argument_nodes, 0..) |argument_declaration_node_index, polymorphic_call_argument_node_index, index| { for (argument_node_list[@intFromBool(is_member.*)..], polymorphic_argument_nodes, 0..) |argument_declaration_node_index, polymorphic_call_argument_node_index, index| {
const argument_declaration_node = unit.getNode(argument_declaration_node_index); const argument_declaration_node = unit.getNode(argument_declaration_node_index);
const argument_type = try builder.resolveType(unit, context, argument_declaration_node.left, &.{}); const argument_type = try builder.resolveType(unit, context, argument_declaration_node.left, &.{});
@ -6922,6 +6976,8 @@ pub const Builder = struct {
} }
} }
function_prototype.has_polymorphic_parameters = true;
// function_prototype.comptime_parameter_declarations = comptime_parameter_declarations.slice(); // function_prototype.comptime_parameter_declarations = comptime_parameter_declarations.slice();
// function_prototype.comptime_parameter_instantiations = comptime_parameter_instantiations.slice(); // function_prototype.comptime_parameter_instantiations = comptime_parameter_instantiations.slice();
} else { } else {
@ -8526,7 +8582,7 @@ pub const Builder = struct {
}; };
} }
fn resolveFunctionDefinition(builder: *Builder, unit: *Unit, context: *const Context, maybe_function_type_index: Type.Index, function_node_index: Node.Index, body_node_index: Node.Index, argument_list_node_index: Node.Index, global_attributes: Debug.Declaration.Global.Attributes, maybe_member_value: ?V, polymorphic_argument_nodes: []const Node.Index, maybe_polymorphic_function: ?*PolymorphicFunction) !V.Comptime { fn resolveFunctionDefinition(builder: *Builder, unit: *Unit, context: *const Context, maybe_function_type_index: Type.Index, function_node_index: Node.Index, body_node_index: Node.Index, argument_list_node_index: Node.Index, global_attributes: Debug.Declaration.Global.Attributes, maybe_member_value: ?V, polymorphic_argument_nodes: []const Node.Index, maybe_global: ?*Debug.Declaration.Global) !V.Comptime {
const current_basic_block = builder.current_basic_block; const current_basic_block = builder.current_basic_block;
defer builder.current_basic_block = current_basic_block; defer builder.current_basic_block = current_basic_block;
builder.current_basic_block = .null; builder.current_basic_block = .null;
@ -8571,10 +8627,18 @@ pub const Builder = struct {
defer builder.popScope(unit, context) catch unreachable; defer builder.popScope(unit, context) catch unreachable;
var comptime_parameter_declarations = UnpinnedArray(ComptimeParameterDeclaration){}; var comptime_parameter_declarations = UnpinnedArray(ComptimeParameterDeclaration){};
var comptime_parameter_instantiations = UnpinnedArray(V.Comptime){};
var is_member_call = false; var is_member_call = false;
function.type = if (maybe_function_type_index == .null) b: { function.type = if (maybe_function_type_index == .null) b: {
const function_prototype_node_index = function_node.left; const function_prototype_node_index = function_node.left;
break :b try builder.resolveFunctionPrototype(unit, context, function_prototype_node_index, global_attributes, maybe_member_value, polymorphic_argument_nodes, &function.scope, &comptime_parameter_declarations, &is_member_call); const function_prototype_index = try builder.resolveFunctionPrototype(unit, context, function_prototype_node_index, global_attributes, maybe_member_value, polymorphic_argument_nodes, &function.scope, &comptime_parameter_declarations, &comptime_parameter_instantiations, &is_member_call, maybe_global);
if (maybe_global) |g| {
switch (g.initial_value) {
.polymorphic_function => |*pf| if (pf.get_instantiation(comptime_parameter_instantiations.slice())) |_| unreachable else {},
else => {},
}
}
break :b function_prototype_index;
} else maybe_function_type_index; } else maybe_function_type_index;
const entry_basic_block = try builder.newBasicBlock(unit, context); const entry_basic_block = try builder.newBasicBlock(unit, context);
@ -9035,16 +9099,19 @@ pub const Builder = struct {
const current_function = builder.current_function; const current_function = builder.current_function;
if (maybe_polymorphic_function) |polymorphic_function| { if (maybe_global != null and maybe_global.?.initial_value == .polymorphic_function) {
_ = polymorphic_function; // autofix const polymorphic_function = &maybe_global.?.initial_value.polymorphic_function;
unreachable; const instantiation = try polymorphic_function.add_instantiation(unit, context, comptime_parameter_instantiations.slice(), maybe_global orelse unreachable, current_function);
return .{
.global = instantiation,
};
} else if (comptime_parameter_declarations.length > 0) { } else if (comptime_parameter_declarations.length > 0) {
var polymorphic_function = PolymorphicFunction{ var polymorphic_function = PolymorphicFunction{
.node = function_node_index, .node = function_node_index,
.parameters = comptime_parameter_declarations.slice(), .parameters = comptime_parameter_declarations.slice(),
.is_member_call = is_member_call, .is_member_call = is_member_call,
}; };
_ =&polymorphic_function; _ = try polymorphic_function.add_instantiation(unit, context, comptime_parameter_instantiations.slice(), maybe_global orelse unreachable, current_function);
return V.Comptime{ return V.Comptime{
.polymorphic_function = polymorphic_function, .polymorphic_function = polymorphic_function,
}; };
@ -9131,7 +9198,7 @@ pub const Builder = struct {
// const function_type_index = try builder.resolveFunctionPrototype(unit, context, function_prototype_node_index, global_attributes, maybe_member_value, polymorphic_argument_nodes); // const function_type_index = try builder.resolveFunctionPrototype(unit, context, function_prototype_node_index, global_attributes, maybe_member_value, polymorphic_argument_nodes);
const function_definition = try builder.resolveFunctionDefinition(unit, context, .null, node_index, body_node_index, argument_list_node_index, global_attributes, maybe_member_value, polymorphic_argument_nodes, null); const function_definition = try builder.resolveFunctionDefinition(unit, context, .null, node_index, body_node_index, argument_list_node_index, global_attributes, maybe_member_value, polymorphic_argument_nodes, maybe_global);
return function_definition; return function_definition;
}, },
@ -9232,7 +9299,7 @@ pub const Builder = struct {
}, },
.function_prototype => { .function_prototype => {
var b = false; var b = false;
const function_prototype = try builder.resolveFunctionPrototype(unit, context, node_index, global_attributes, null, &.{}, null, null, &b); const function_prototype = try builder.resolveFunctionPrototype(unit, context, node_index, global_attributes, null, &.{}, null, null, null, &b, null);
if (global_attributes.contains(.@"extern")) { if (global_attributes.contains(.@"extern")) {
return .{ return .{
.function_declaration = function_prototype, .function_declaration = function_prototype,
@ -12532,6 +12599,7 @@ pub const Builder = struct {
} }
} else if (struct_type.scope.scope.lookupDeclaration(right_identifier_hash, false)) |lookup| { } else if (struct_type.scope.scope.lookupDeclaration(right_identifier_hash, false)) |lookup| {
const right_symbol = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration, .{}, &.{}, value, argument_nodes); const right_symbol = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration, .{}, &.{}, value, argument_nodes);
assert(right_symbol.initial_value != .polymorphic_function);
switch (right_symbol.initial_value) { switch (right_symbol.initial_value) {
.function_definition => { .function_definition => {
const function_type_index = right_symbol.declaration.type; const function_type_index = right_symbol.declaration.type;

View File

@ -133,7 +133,6 @@ const Arena = struct{
} }
const allocate = fn (arena: &Arena, size: u64) *!&any { const allocate = fn (arena: &Arena, size: u64) *!&any {
if (arena.position + size <= arena.size) { if (arena.position + size <= arena.size) {
const base: &any = #cast(arena); const base: &any = #cast(arena);
var post_alignment_position = arena.position + arena.alignment - 1; var post_alignment_position = arena.position + arena.alignment - 1;

View File

@ -3,19 +3,43 @@ const Arena = std.Arena;
const c_slice = std.c_slice; const c_slice = std.c_slice;
const byte_equal = std.byte_equal; const byte_equal = std.byte_equal;
const print = std.print; const print = std.print;
const print_usize = std.print_usize;
const exit = std.os.exit; const exit = std.os.exit;
const ArgumentProcessingError = error{ const ArgumentProcessingError = error{
no_arguments, no_arguments,
}; };
const lex = fn (arena: &Arena, bytes: []const u8) void { const lex = fn (arena: &Arena, bytes: []const u8) *!void {
if (bytes.length >= 0xffffffff) { if (bytes.length >= 0xffffffff) {
unreachable; unreachable;
} }
const length: u32 = #cast(bytes.length); const length: u32 = #cast(bytes.length);
var i: u32 = 0; var i: u32 = 0;
const line_offset_arena = try Arena.init(bytes.length + #size(Arena));
var line_offsets = try line_offset_arena.new_array($u32, bytes.length);
line_offsets[0] = 0;
var line_count: u32 = 1;
var index: u32 = 0;
while (index < length) {
const byte = bytes[index];
line_offsets[line_count] = index;
line_count += #cast(byte == '\n');
index += 1;
}
print("Line count: ");
print_usize(line_count);
print("\n");
for (line_offsets[0..line_count]) |offset| {
print_usize(offset);
print("\n");
}
} }
const get_argument = fn (real_argument: []const u8, wanted_argument: []const u8, command_arguments: []const [&:0]const u8, i_ptr: &usize) ?[]const u8 { const get_argument = fn (real_argument: []const u8, wanted_argument: []const u8, command_arguments: []const [&:0]const u8, i_ptr: &usize) ?[]const u8 {