fix(0118): cast accepts compound type args; compound type literals are first-class Type values
This commit is contained in:
@@ -387,25 +387,16 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
|
||||
};
|
||||
|
||||
// Handle cast(TargetType, val) — emit conversion instructions
|
||||
// Only for compile-time known types (type_expr or known type names)
|
||||
// for any compile-time-resolvable type argument. The gate is the
|
||||
// canonical `isStaticTypeArg` (the one `type_name`/`type_eq` use),
|
||||
// so compound shapes (`*T`, `[]T`, `?T`, `[*]T`, `[N]T`) resolve
|
||||
// statically instead of falling into the runtime-dispatch path
|
||||
// and dying unresolved (issue 0118). An identifier bound in scope
|
||||
// as a runtime `Type` value (the `cast(type) val` category-arm
|
||||
// form) still classifies as non-static and falls through.
|
||||
if (std.mem.eql(u8, id.name, "cast") and c.args.len >= 2) {
|
||||
const type_arg = c.args[0];
|
||||
const is_static_type = blk: {
|
||||
if (type_arg.data == .type_expr) break :blk true;
|
||||
if (type_arg.data == .identifier) {
|
||||
const tname = type_arg.data.identifier.name;
|
||||
// Check if it's a known type name (not a runtime variable)
|
||||
if (type_bridge.resolveTypePrimitive(tname) != null) break :blk true;
|
||||
if (self.type_bindings) |bindings| {
|
||||
if (bindings.get(tname) != null) break :blk true;
|
||||
}
|
||||
// Check if it's a registered struct/enum type name
|
||||
const name_id = self.module.types.internString(tname);
|
||||
if (self.module.types.findByName(name_id) != null) break :blk true;
|
||||
}
|
||||
break :blk false;
|
||||
};
|
||||
if (is_static_type) {
|
||||
if (self.isStaticTypeArg(type_arg)) {
|
||||
const dst_ty = self.resolveTypeArg(c.args[0]);
|
||||
const val = args.items[1]; // already lowered
|
||||
const src_ty = self.inferExprType(c.args[1]);
|
||||
|
||||
@@ -2021,6 +2021,25 @@ pub fn lowerExpr(self: *Lowering, node: *const Node) Ref {
|
||||
break :blk self.emitError(te.name, node.span);
|
||||
},
|
||||
|
||||
// Compound type literals (`*T`, `[]T`, `[*]T`, `?T`, `[N]T`, fn types)
|
||||
// in expression position are first-class `Type` values, exactly like
|
||||
// the named form above (`t : Type = *s64;` ↔ `t : Type = f64;`). Also
|
||||
// the path a static `cast(*s64) v` type argument takes — call args are
|
||||
// lowered before the cast handler inspects the AST (issue 0118).
|
||||
.pointer_type_expr,
|
||||
.many_pointer_type_expr,
|
||||
.slice_type_expr,
|
||||
.optional_type_expr,
|
||||
.array_type_expr,
|
||||
.function_type_expr,
|
||||
=> blk: {
|
||||
const ty = self.resolveTypeWithBindings(node);
|
||||
// The resolver diagnosed any unresolved leaf; don't mint a Type
|
||||
// value around the failure sentinel.
|
||||
if (ty == .unresolved) break :blk self.emitError("unknown_expr", node.span);
|
||||
break :blk self.builder.constType(ty);
|
||||
},
|
||||
|
||||
.try_expr => |te| self.lowerTry(te.operand, node.span),
|
||||
.catch_expr => |ce| self.lowerCatch(&ce, node.span),
|
||||
.caller_location => self.lowerCallerLocation(node),
|
||||
|
||||
Reference in New Issue
Block a user