This commit is contained in:
agra
2026-02-19 01:26:04 +02:00
parent fbf8a62362
commit e0e655cd36
11 changed files with 938 additions and 25 deletions

View File

@@ -24,6 +24,7 @@ pub const Type = union(enum) {
function_type: FunctionTypeInfo,
any_type,
meta_type: MetaTypeInfo,
tuple_type: TupleTypeInfo,
pub const SliceTypeInfo = struct {
element_name: []const u8,
@@ -56,6 +57,11 @@ pub const Type = union(enum) {
name: []const u8,
};
pub const TupleTypeInfo = struct {
field_names: ?[]const []const u8, // null for positional tuples
field_types: []const Type,
};
/// Content-based equality: compares string fields by content, not pointer identity.
pub fn eql(self: Type, other: Type) bool {
const Tag = std.meta.Tag(Type);
@@ -85,6 +91,20 @@ pub const Type = union(enum) {
return info.return_type.eql(o.return_type.*);
},
.meta_type => |info| std.mem.eql(u8, info.name, other.meta_type.name),
.tuple_type => |info| {
const o = other.tuple_type;
if (info.field_types.len != o.field_types.len) return false;
for (info.field_types, o.field_types) |a, b| {
if (!a.eql(b)) return false;
}
// If both have names, compare them
if (info.field_names != null and o.field_names != null) {
for (info.field_names.?, o.field_names.?) |a, b| {
if (!std.mem.eql(u8, a, b)) return false;
}
}
return true;
},
};
}
@@ -185,6 +205,13 @@ pub const Type = union(enum) {
};
}
pub fn isTuple(self: Type) bool {
return switch (self) {
.tuple_type => true,
else => false,
};
}
pub fn isAny(self: Type) bool {
return switch (self) {
.any_type => true,
@@ -344,6 +371,17 @@ pub const Type = union(enum) {
return std.mem.eql(u8, target.pointer_type.pointee_name, "void");
}
// Tuple → tuple: same field count and each field implicitly convertible
if (self.isTuple() and target.isTuple()) {
const si = self.tuple_type;
const ti = target.tuple_type;
if (si.field_types.len != ti.field_types.len) return false;
for (si.field_types, ti.field_types) |sf, tf| {
if (!sf.isImplicitlyConvertibleTo(tf)) return false;
}
return true;
}
const src_float = self.isFloat();
const dst_float = target.isFloat();
const src_int = self.isInt();
@@ -424,6 +462,20 @@ pub const Type = union(enum) {
return try buf.toOwnedSlice(allocator);
},
.meta_type => |info| info.name,
.tuple_type => |info| {
var buf = std.ArrayList(u8).empty;
try buf.append(allocator, '(');
for (info.field_types, 0..) |ft, i| {
if (i > 0) try buf.appendSlice(allocator, ", ");
if (info.field_names) |names| {
try buf.appendSlice(allocator, names[i]);
try buf.appendSlice(allocator, ": ");
}
try buf.appendSlice(allocator, try ft.displayName(allocator));
}
try buf.append(allocator, ')');
return try buf.toOwnedSlice(allocator);
},
};
}
@@ -433,6 +485,11 @@ pub const Type = union(enum) {
// Same type → return it
if (a.eql(b)) return a;
// Tuple + tuple → return a if same field count
if (a.isTuple() and b.isTuple()) {
if (a.tuple_type.field_types.len == b.tuple_type.field_types.len) return a;
}
// Vector + vector of same dimensions → return a
if (a.isVector() and b.isVector()) return a;
// Vector + scalar → return vector (scalar will be broadcast)