optionals

This commit is contained in:
agra
2026-02-22 22:16:30 +02:00
parent d3e574eae5
commit 1cc67f9b5a
17 changed files with 1952 additions and 32 deletions

View File

@@ -278,6 +278,13 @@ pub const Analyzer = struct {
const elem_name = elem_type.displayName(self.allocator) catch return .void_type;
return .{ .slice_type = .{ .element_name = elem_name } };
}
// Optional type: ?T
if (tn.data == .optional_type_expr) {
const ote = tn.data.optional_type_expr;
const inner_type = self.resolveTypeNode(ote.inner_type);
const inner_name = inner_type.displayName(self.allocator) catch return .void_type;
return .{ .optional_type = .{ .child_name = inner_name } };
}
// Pointer type: *T
if (tn.data == .pointer_type_expr) {
const pte = tn.data.pointer_type_expr;
@@ -456,6 +463,16 @@ pub const Analyzer = struct {
}
return .void_type;
},
.force_unwrap => |fu| {
const opt_ty = self.inferExprType(fu.operand);
if (opt_ty.isOptional()) return Type.fromName(opt_ty.optional_type.child_name) orelse .void_type;
return .void_type;
},
.null_coalesce => |nc| {
const opt_ty = self.inferExprType(nc.lhs);
if (opt_ty.isOptional()) return Type.fromName(opt_ty.optional_type.child_name) orelse .void_type;
return self.inferExprType(nc.rhs);
},
.deref_expr => |de| {
const ptr_ty = self.inferExprType(de.operand);
if (ptr_ty.isPointer()) return ptr_ty.pointerPointeeType() orelse .void_type;
@@ -711,7 +728,20 @@ pub const Analyzer = struct {
},
.if_expr => |ie| {
try self.analyzeNode(ie.condition);
try self.analyzeNode(ie.then_branch);
if (ie.binding_name) |bname| {
// `if val := expr { ... }` — val is the unwrapped optional
const cond_ty = self.inferExprType(ie.condition);
const inner_ty: ?Type = if (cond_ty.isOptional())
Type.fromName(cond_ty.optional_type.child_name)
else
null;
try self.pushScope();
try self.addSymbol(bname, .variable, inner_ty, node.span);
try self.analyzeNode(ie.then_branch);
self.popScope();
} else {
try self.analyzeNode(ie.then_branch);
}
if (ie.else_branch) |eb| {
try self.analyzeNode(eb);
}
@@ -729,7 +759,19 @@ pub const Analyzer = struct {
},
.while_expr => |we| {
try self.analyzeNode(we.condition);
try self.analyzeNode(we.body);
if (we.binding_name) |bname| {
const cond_ty = self.inferExprType(we.condition);
const inner_ty: ?Type = if (cond_ty.isOptional())
Type.fromName(cond_ty.optional_type.child_name)
else
null;
try self.pushScope();
try self.addSymbol(bname, .variable, inner_ty, node.span);
try self.analyzeNode(we.body);
self.popScope();
} else {
try self.analyzeNode(we.body);
}
},
.for_expr => |fe| {
try self.analyzeNode(fe.iterable);
@@ -812,6 +854,7 @@ pub const Analyzer = struct {
.slice_type_expr,
.pointer_type_expr,
.many_pointer_type_expr,
.optional_type_expr,
.null_literal,
.array_literal,
.parameterized_type_expr,
@@ -829,6 +872,13 @@ pub const Analyzer = struct {
try self.analyzeNode(elem.value);
}
},
.force_unwrap => |fu| {
try self.analyzeNode(fu.operand);
},
.null_coalesce => |nc| {
try self.analyzeNode(nc.lhs);
try self.analyzeNode(nc.rhs);
},
.deref_expr => |de| {
try self.analyzeNode(de.operand);
},
@@ -864,6 +914,8 @@ pub const Analyzer = struct {
.index_expr,
.slice_expr,
.deref_expr,
.force_unwrap,
.null_coalesce,
.null_literal,
.type_expr,
.insert_expr,
@@ -905,7 +957,17 @@ pub const Analyzer = struct {
}
}
}
// For compound types (pointers, slices, arrays), resolve inner type refs
// Compound types: ?T, *T, [*]T, []T, [N]T — delegate to resolveTypeNode
switch (tn.data) {
.optional_type_expr, .pointer_type_expr, .many_pointer_type_expr,
.slice_type_expr, .array_type_expr,
=> {
const resolved = self.resolveTypeNode(tn);
if (resolved != .void_type) return resolved;
},
else => {},
}
// For compound types, resolve inner type refs
self.resolveTypeRef(tn);
}
return null;
@@ -950,6 +1012,9 @@ pub const Analyzer = struct {
.array_type_expr => |ate| {
self.resolveTypeRef(ate.element_type);
},
.optional_type_expr => |ote| {
self.resolveTypeRef(ote.inner_type);
},
else => {},
}
}
@@ -1152,6 +1217,7 @@ pub fn findNodeAtOffset(node: *Node, offset: u32) ?*Node {
.slice_type_expr,
.pointer_type_expr,
.many_pointer_type_expr,
.optional_type_expr,
.null_literal,
.array_literal,
.parameterized_type_expr,
@@ -1165,6 +1231,13 @@ pub fn findNodeAtOffset(node: *Node, offset: u32) ?*Node {
if (findNodeAtOffset(elem.value, offset)) |found| return found;
}
},
.null_coalesce => |nc| {
if (findNodeAtOffset(nc.lhs, offset)) |found| return found;
if (findNodeAtOffset(nc.rhs, offset)) |found| return found;
},
.force_unwrap => |fu| {
if (findNodeAtOffset(fu.operand, offset)) |found| return found;
},
.deref_expr => |de| {
if (findNodeAtOffset(de.operand, offset)) |found| return found;
},