feat(lang): raw provenance through ALL sema compound type metadata — finish universal raw identifier in the LSP classifier [F0.6]
The codegen-side resolver was already raw-aware for the universal model; the sema/LSP editor index (the second classifier) only honored the DIRECT raw type. A COMPOUND raw type (`*`s2`, `?`s2`, `[N]`s2`, `[]`s2`, `[*]`s2`) stores its inner type-name as a bare string on the Type info struct, and every resolution site re-read it with skip_builtin=false — so the index reclassified a user type named `s2` as the builtin int, diverging from codegen (issue-0083 class, LSP surface only; codegen unchanged). Structural cure: every compound info struct (Pointer/Optional/Slice/ ManyPointer/Array) carries a REQUIRED is_raw bit (no default — a future construction site cannot drop it). is_raw is set at every construction site (resolveTypeNode arms, fieldType arms, variadic slice, .ptr/slice_expr derivation, for-loop by-ref, substType) and passed as skip_builtin at every resolution site (elementTypeOf, field-access pointer unwrap, index, deref, optional unwrap/null-coalesce, if/while optional binding, match subject). Optional-unwrap + deref sites converted from Type.fromName/pointerPointeeType (builtin-only, divergent) to resolveTypeNameStr(name, is_raw); the now-dead pointerPointeeType removed. Tests: src/sema.test.zig gains pointer/optional/array raw-vs-bare regressions (raw → user type, bare → builtin control) — each FAILS on pre-fix sema, PASSES after — plus a parameterized-raw coverage test.
This commit is contained in:
@@ -42,16 +42,26 @@ pub const Type = union(enum) {
|
||||
/// `ir.TypeId.unresolved`.
|
||||
unresolved,
|
||||
|
||||
/// `is_raw` records whether the inner type-name came from a backtick raw
|
||||
/// reference (`` `s2 ``) or an already-resolved user type. It is the
|
||||
/// `skip_builtin` the resolver MUST pass when re-resolving the stored inner
|
||||
/// name (issue 0089) — without it `resolveTypeNameStr` would reclassify a
|
||||
/// user type named `s2` as the builtin int, diverging from codegen. The
|
||||
/// field is REQUIRED (no default) so a future construction site cannot
|
||||
/// silently drop the bit, the way the LSP index did for compound shapes.
|
||||
pub const SliceTypeInfo = struct {
|
||||
element_name: []const u8,
|
||||
is_raw: bool,
|
||||
};
|
||||
|
||||
pub const PointerTypeInfo = struct {
|
||||
pointee_name: []const u8,
|
||||
is_raw: bool,
|
||||
};
|
||||
|
||||
pub const ManyPointerTypeInfo = struct {
|
||||
element_name: []const u8,
|
||||
is_raw: bool,
|
||||
};
|
||||
|
||||
pub const FunctionTypeInfo = struct {
|
||||
@@ -67,6 +77,7 @@ pub const Type = union(enum) {
|
||||
pub const ArrayTypeInfo = struct {
|
||||
element_name: []const u8,
|
||||
length: u32,
|
||||
is_raw: bool,
|
||||
};
|
||||
|
||||
pub const VectorTypeInfo = struct {
|
||||
@@ -76,6 +87,7 @@ pub const Type = union(enum) {
|
||||
|
||||
pub const OptionalTypeInfo = struct {
|
||||
child_name: []const u8,
|
||||
is_raw: bool,
|
||||
};
|
||||
|
||||
pub const MetaTypeInfo = struct {
|
||||
@@ -125,7 +137,7 @@ pub const Type = union(enum) {
|
||||
if (std.mem.eql(u8, name, "f64")) return .f64;
|
||||
return null;
|
||||
},
|
||||
'?' => if (name.len >= 2) .{ .optional_type = .{ .child_name = name[1..] } } else null,
|
||||
'?' => if (name.len >= 2) .{ .optional_type = .{ .child_name = name[1..], .is_raw = false } } else null,
|
||||
'A' => if (std.mem.eql(u8, name, "Any")) .any_type else null,
|
||||
'v' => if (std.mem.eql(u8, name, "void")) .void_type else null,
|
||||
'[' => {
|
||||
@@ -141,11 +153,11 @@ pub const Type = union(enum) {
|
||||
}
|
||||
// Many-pointer: [*]T
|
||||
if (name.len >= 4 and name[1] == '*' and name[2] == ']') {
|
||||
return .{ .many_pointer_type = .{ .element_name = name[3..] } };
|
||||
return .{ .many_pointer_type = .{ .element_name = name[3..], .is_raw = false } };
|
||||
}
|
||||
return null;
|
||||
},
|
||||
'*' => if (name.len >= 2) .{ .pointer_type = .{ .pointee_name = name[1..] } } else null,
|
||||
'*' => if (name.len >= 2) .{ .pointer_type = .{ .pointee_name = name[1..], .is_raw = false } } else null,
|
||||
'V' => {
|
||||
// Vector(N,T)
|
||||
if (name.len >= 10 and std.mem.startsWith(u8, name, "Vector(") and name[name.len - 1] == ')') {
|
||||
@@ -235,13 +247,6 @@ pub const Type = union(enum) {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn pointerPointeeType(self: Type) ?Type {
|
||||
return switch (self) {
|
||||
.pointer_type => |info| fromName(info.pointee_name),
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isManyPointer(self: Type) bool {
|
||||
return switch (self) {
|
||||
.many_pointer_type => true,
|
||||
|
||||
Reference in New Issue
Block a user