tuples
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user