mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
Fix more type stuff
This commit is contained in:
parent
5a3f900b6f
commit
07782257a1
6 changed files with 64 additions and 38 deletions
|
|
@ -8303,8 +8303,11 @@ fn canonicalizeTypeAnnoRecord(
|
|||
const record_fields_scratch = self.scratch_record_fields.sliceFromStart(scratch_record_fields_top);
|
||||
std.mem.sort(types.RecordField, record_fields_scratch, self.env.common.getIdentStore(), comptime types.RecordField.sortByNameAsc);
|
||||
|
||||
// TODO: Support record extension syntax in the parser (e.g., `{ name: Str, ..others }`)
|
||||
// For now, all records are closed (ext = null)
|
||||
return try self.env.addTypeAnno(.{ .record = .{
|
||||
.fields = field_anno_idxs,
|
||||
.ext = null,
|
||||
} }, region);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1214,9 +1214,12 @@ pub fn getTypeAnno(store: *const NodeStore, typeAnno: CIR.TypeAnno.Idx) CIR.Type
|
|||
.ty_tuple => return CIR.TypeAnno{ .tuple = .{
|
||||
.elems = .{ .span = .{ .start = node.data_1, .len = node.data_2 } },
|
||||
} },
|
||||
.ty_record => return CIR.TypeAnno{ .record = .{
|
||||
.fields = .{ .span = .{ .start = node.data_1, .len = node.data_2 } },
|
||||
} },
|
||||
.ty_record => return CIR.TypeAnno{
|
||||
.record = .{
|
||||
.fields = .{ .span = .{ .start = node.data_1, .len = node.data_2 } },
|
||||
.ext = null, // TODO: Support record extension in serialization
|
||||
},
|
||||
},
|
||||
.ty_fn => {
|
||||
const extra_data_idx = node.data_3;
|
||||
const effectful = store.extra_data.items.items[extra_data_idx] != 0;
|
||||
|
|
|
|||
|
|
@ -365,6 +365,7 @@ pub const TypeAnno = union(enum) {
|
|||
/// A record in a type annotation
|
||||
pub const Record = struct {
|
||||
fields: RecordField.Span, // The field definitions
|
||||
ext: ?TypeAnno.Idx, // Optional extension variable for open records
|
||||
};
|
||||
|
||||
/// A tag union in a type annotation
|
||||
|
|
|
|||
|
|
@ -968,6 +968,7 @@ test "NodeStore round trip - TypeAnno" {
|
|||
try type_annos.append(gpa, CIR.TypeAnno{
|
||||
.record = .{
|
||||
.fields = CIR.TypeAnno.RecordField.Span{ .span = rand_span() },
|
||||
.ext = null,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1001,9 +1001,8 @@ pub fn checkFile(self: *Self) std.mem.Allocator.Error!void {
|
|||
.s_runtime_error => {
|
||||
try self.unifyWith(stmt_var, .err, &env);
|
||||
},
|
||||
.s_type_anno => |_| {
|
||||
// TODO: Handle standalone type annotations
|
||||
try self.unifyWith(stmt_var, .err, &env);
|
||||
.s_type_anno => |type_anno| {
|
||||
try self.generateStandaloneTypeAnno(stmt_var, type_anno, &env);
|
||||
},
|
||||
else => {
|
||||
// All other stmt types are invalid at the top level
|
||||
|
|
@ -1375,6 +1374,25 @@ fn generateNominalDecl(
|
|||
);
|
||||
}
|
||||
|
||||
/// Generate types for a standalone type annotation (one without a corresponding definition).
|
||||
/// These are typically used for FFI function declarations or forward declarations.
|
||||
fn generateStandaloneTypeAnno(
|
||||
self: *Self,
|
||||
stmt_var: Var,
|
||||
type_anno: std.meta.fieldInfo(CIR.Statement, .s_type_anno).type,
|
||||
env: *Env,
|
||||
) std.mem.Allocator.Error!void {
|
||||
// Generate the type from the annotation
|
||||
self.seen_annos.clearRetainingCapacity();
|
||||
const anno_var: Var = ModuleEnv.varFrom(type_anno.anno);
|
||||
try self.generateAnnoTypeInPlace(type_anno.anno, env, .annotation);
|
||||
|
||||
// Unify the statement variable with the generated annotation type
|
||||
_ = try self.unify(stmt_var, anno_var, env);
|
||||
|
||||
// TODO: Handle where clauses if present (type_anno.where)
|
||||
}
|
||||
|
||||
/// Generate types for type anno args
|
||||
fn generateHeaderVars(
|
||||
self: *Self,
|
||||
|
|
@ -1952,17 +1970,13 @@ fn generateAnnoTypeInPlace(self: *Self, anno_idx: CIR.TypeAnno.Idx, env: *Env, c
|
|||
std.mem.sort(types_mod.RecordField, record_fields_slice, self.cir.common.getIdentStore(), comptime types_mod.RecordField.sortByNameAsc);
|
||||
const fields_type_range = try self.types.appendRecordFields(record_fields_slice);
|
||||
|
||||
// Process the ext if it exists. Absence means it's a closed union
|
||||
// TODO: Capture ext in record field CIR
|
||||
// const ext_var = inner_blk: {
|
||||
// if (rec.ext) |ext_anno_idx| {
|
||||
// try self.generateAnnoType(rigid_vars_ctx, ext_anno_idx);
|
||||
// break :inner_blk ModuleEnv.varFrom(ext_anno_idx);
|
||||
// } else {
|
||||
// break :inner_blk try self.freshFromContent(.{ .structure = .empty_record }, rank, anno_region);
|
||||
// }
|
||||
// };
|
||||
const ext_var = try self.freshFromContent(.{ .structure = .empty_record }, env, anno_region);
|
||||
// Process the ext if it exists. Absence (null) means it's a closed record.
|
||||
const ext_var = if (rec.ext) |ext_anno_idx| blk: {
|
||||
try self.generateAnnoTypeInPlace(ext_anno_idx, env, ctx);
|
||||
break :blk ModuleEnv.varFrom(ext_anno_idx);
|
||||
} else blk: {
|
||||
break :blk try self.freshFromContent(.{ .structure = .empty_record }, env, anno_region);
|
||||
};
|
||||
|
||||
// Create the type for the anno in the store
|
||||
try self.unifyWith(
|
||||
|
|
@ -2853,7 +2867,9 @@ fn checkExpr(self: *Self, expr_idx: CIR.Expr.Idx, env: *Env, expected: Expected)
|
|||
try self.checkDef(processing_def.def_idx, &sub_env);
|
||||
},
|
||||
.processing => {
|
||||
// TODO: Handle recursive defs
|
||||
// Recursive reference - the pattern variable is still at
|
||||
// top_level rank (not generalized), so the code below will
|
||||
// unify directly with it, which is the correct behavior.
|
||||
},
|
||||
.processed => {},
|
||||
}
|
||||
|
|
@ -5024,7 +5040,9 @@ fn checkDeferredStaticDispatchConstraints(self: *Self, env: *Env) std.mem.Alloca
|
|||
try self.checkDef(def_idx, &sub_env);
|
||||
},
|
||||
.processing => {
|
||||
// TODO: Handle recursive defs
|
||||
// Recursive reference during static dispatch resolution.
|
||||
// The def is still being processed, so we'll use its
|
||||
// current (non-generalized) type.
|
||||
},
|
||||
.processed => {},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1272,54 +1272,54 @@ const Unifier = struct {
|
|||
///
|
||||
/// **Case 1: Exactly the Same Fields**
|
||||
///
|
||||
/// a = { x, y }ext_a
|
||||
/// b = { x, y }ext_b
|
||||
/// a = { x, y, ..others_a }
|
||||
/// b = { x, y, ..others_b }
|
||||
///
|
||||
/// - All fields are shared
|
||||
/// - We unify `ext_a ~ ext_b`
|
||||
/// - We unify `others_a ~ others_b`
|
||||
/// - Then unify each shared field pair
|
||||
///
|
||||
/// ---
|
||||
///
|
||||
/// **Case 2: `a` Extends `b`**
|
||||
///
|
||||
/// a = { x, y, z }ext_a
|
||||
/// b = { x, y }ext_b
|
||||
/// a = { x, y, z, ..others_a }
|
||||
/// b = { x, y, ..others_b }
|
||||
///
|
||||
/// - `a` has additional fields not in `b`
|
||||
/// - We generate a new var `only_in_a_var = { z }ext_a`
|
||||
/// - Unify `only_in_a_var ~ ext_b`
|
||||
/// - We generate a new var `only_in_a_var = { z, ..others_a }`
|
||||
/// - Unify `only_in_a_var ~ others_b`
|
||||
/// - Then unify shared fields
|
||||
///
|
||||
/// ---
|
||||
///
|
||||
/// **Case 3: `b` Extends `a`**
|
||||
///
|
||||
/// a = { x, y }ext_a
|
||||
/// b = { x, y, z }ext_b
|
||||
/// a = { x, y, ..others_a }
|
||||
/// b = { x, y, z, ..others_b }
|
||||
///
|
||||
/// - Same as Case 2, but reversed
|
||||
/// - `b` has additional fields not in `a`
|
||||
/// - We generate a new var `only_in_b_var = { z }ext_b`
|
||||
/// - Unify `ext_a ~ only_in_b_var`
|
||||
/// - We generate a new var `only_in_b_var = { z, ..others_b }`
|
||||
/// - Unify `others_a ~ only_in_b_var`
|
||||
/// - Then unify shared fields
|
||||
///
|
||||
/// ---
|
||||
///
|
||||
/// **Case 4: Both Extend Each Other**
|
||||
///
|
||||
/// a = { x, y, z }ext_a
|
||||
/// b = { x, y, w }ext_b
|
||||
/// a = { x, y, z, ..others_a }
|
||||
/// b = { x, y, w, ..others_b }
|
||||
///
|
||||
/// - Each has unique fields the other lacks
|
||||
/// - Generate:
|
||||
/// - shared_ext = fresh flex_var
|
||||
/// - only_in_a_var = { z }shared_ext
|
||||
/// - only_in_b_var = { w }shared_ext
|
||||
/// - shared_others = fresh flex_var
|
||||
/// - only_in_a_var = { z, ..shared_others }
|
||||
/// - only_in_b_var = { w, ..shared_others }
|
||||
/// - Unify:
|
||||
/// - `ext_a ~ only_in_b_var`
|
||||
/// - `only_in_a_var ~ ext_b`
|
||||
/// - Then unify shared fields into `{ x, y }shared_ext`
|
||||
/// - `others_a ~ only_in_b_var`
|
||||
/// - `only_in_a_var ~ others_b`
|
||||
/// - Then unify shared fields into `{ x, y, ..shared_others }`
|
||||
///
|
||||
/// ---
|
||||
///
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue