ffi issue-0049: resolveParamType + packVariadicCallArgs unwrap new-form slice
Both helpers now detect when a variadic param's declared type is already a slice (`..name: []T`) and use it as the element-shape container directly, instead of wrapping it once more. The legacy form (`name: ..T`) still wraps as before. Without the unwrap, the new-form `..parts: []string` ends up with a callee-side slot type of `[]([]string)`, while the call-site marshal pack emits a `[N x string]` array, and downstream LLVM emission crashes on the resulting null Refs (`LLVMBuildExtractValue` inside `emitStrCmp`). `examples/121-ios-sim-bundle.sx` (which exercises stdlib's migrated `path_join`) and the focused regression `examples/174-new-form-variadic-cross-module.sx` both flip green; suite stays at 214/214. The remaining stdlib decls (`format` / `print` / `open`) and example fixtures land in the follow-up migration commit.
This commit is contained in:
@@ -7677,13 +7677,22 @@ pub const Lowering = struct {
|
|||||||
if (fd.body.data == .foreign_expr and fd.params.len > 0 and fd.params[fd.params.len - 1].is_variadic) {
|
if (fd.body.data == .foreign_expr and fd.params.len > 0 and fd.params[fd.params.len - 1].is_variadic) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Find variadic param index
|
// Find variadic param index. The two surface forms differ in
|
||||||
|
// what `p.type_expr` resolves to: legacy `name: ..T` declares T
|
||||||
|
// (element type), new `..name: []T` declares []T (already a
|
||||||
|
// slice). Unwrap the latter so the per-element packing below
|
||||||
|
// sees T in both cases.
|
||||||
var variadic_idx: ?usize = null;
|
var variadic_idx: ?usize = null;
|
||||||
var elem_ty: TypeId = .any;
|
var elem_ty: TypeId = .any;
|
||||||
for (fd.params, 0..) |p, i| {
|
for (fd.params, 0..) |p, i| {
|
||||||
if (p.is_variadic) {
|
if (p.is_variadic) {
|
||||||
variadic_idx = i;
|
variadic_idx = i;
|
||||||
elem_ty = self.resolveTypeWithBindings(p.type_expr);
|
const declared = self.resolveTypeWithBindings(p.type_expr);
|
||||||
|
elem_ty = declared;
|
||||||
|
if (!declared.isBuiltin()) {
|
||||||
|
const info = self.module.types.get(declared);
|
||||||
|
if (info == .slice) elem_ty = info.slice.element;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9999,12 +10008,23 @@ pub const Lowering = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn resolveParamType(self: *Lowering, p: *const ast.Param) TypeId {
|
fn resolveParamType(self: *Lowering, p: *const ast.Param) TypeId {
|
||||||
const elem_ty = self.resolveTypeWithBindings(p.type_expr);
|
const declared_ty = self.resolveTypeWithBindings(p.type_expr);
|
||||||
if (p.is_variadic) {
|
if (p.is_variadic) {
|
||||||
// Variadic param (..T) → receives a []T slice
|
// Two surface forms:
|
||||||
return self.module.types.sliceOf(elem_ty);
|
// - legacy `name: ..T` — declared_ty is the element type;
|
||||||
|
// wrap to receive a `[]T` slice.
|
||||||
|
// - new `..name: []T` — declared_ty is already the slice
|
||||||
|
// type; use it as-is. Wrapping here would double up to
|
||||||
|
// `[][]T` and downstream LLVM emission crashes when the
|
||||||
|
// caller's argument-marshal pack produces a `[]T` that
|
||||||
|
// doesn't match the callee's stored param shape.
|
||||||
|
if (!declared_ty.isBuiltin()) {
|
||||||
|
const info = self.module.types.get(declared_ty);
|
||||||
|
if (info == .slice) return declared_ty;
|
||||||
|
}
|
||||||
|
return self.module.types.sliceOf(declared_ty);
|
||||||
}
|
}
|
||||||
return elem_ty;
|
return declared_ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolveType(self: *Lowering, type_ann: *const Node) TypeId {
|
fn resolveType(self: *Lowering, type_ann: *const Node) TypeId {
|
||||||
|
|||||||
Reference in New Issue
Block a user