Skip to content

Commit 7aa7c0b

Browse files
joskeclaude
andcommitted
fix: resolve TypeParameter(0) panic in Tuple type handling
Pass tyvec through to recursive calls in to_llvm_type's Tuple arm instead of discarding it with &[], and return None gracefully when elements can't be resolved. Reorder declare_native_function to check type_has_type_params before is_tuple_return so tuples with unresolved type params use the generic return path. Make _return_val_is_tuple mutually exclusive with return_val_is_generic at the call site. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b1e6288 commit 7aa7c0b

2 files changed

Lines changed: 19 additions & 21 deletions

File tree

crates/move-to-polka/src/stackless/module_context.rs

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -827,23 +827,23 @@ impl<'mm: 'up, 'up> ModuleContext<'mm, 'up> {
827827
matches!(&fn_data.result_type, mty::Type::Tuple(ts) if ts.len() > 1);
828828
let (ll_rty, ll_byref_rty) = if mty0.is_type_parameter() {
829829
(llcx.void_type(), Some(llcx.ptr_type()))
830-
} else if is_tuple_return {
831-
// Tuple returns: return the LAST field in a register,
832-
// pass pointers for preceding fields as extra args.
833-
if let mty::Type::Tuple(ts) = &fn_data.result_type {
834-
let last_ty = self.to_llvm_type(ts.last().unwrap(), &[]).unwrap();
835-
(last_ty, None)
836-
} else {
837-
(self.to_llvm_type(mty0, &[]).unwrap(), None)
838-
}
839830
} else if !mty0.is_reference()
840831
&& !mty0.is_vector()
841832
&& Self::type_has_type_params(mty0)
842833
{
843-
// Struct return with unresolved type params (e.g. Box<V>)
834+
// Tuples or structs with unresolved type params (e.g. Box<V>)
844835
// → return via output pointer, like generic returns.
845836
// Vectors are excluded: they always have fixed layout (MoveUntypedVector).
846837
(llcx.void_type(), Some(llcx.ptr_type()))
838+
} else if is_tuple_return {
839+
// Tuple returns (concrete types only): return the LAST field
840+
// in a register, pass pointers for preceding fields as extra args.
841+
if let mty::Type::Tuple(ts) = &fn_data.result_type {
842+
let last_ty = self.to_llvm_type(ts.last().unwrap(), &[]).unwrap();
843+
(last_ty, None)
844+
} else {
845+
(self.to_llvm_type(mty0, &[]).unwrap(), None)
846+
}
847847
} else {
848848
(self.to_llvm_type(mty0, &[]).unwrap(), None)
849849
};
@@ -1005,18 +1005,15 @@ impl<'mm: 'up, 'up> ModuleContext<'mm, 'up> {
10051005
if types_vec.is_empty() {
10061006
Some(self.llvm_cx.void_type())
10071007
} else {
1008-
let llvm_types = types_vec
1008+
let llvm_types: Option<Vec<_>> = types_vec
10091009
.iter()
1010-
.map(|move_type| {
1011-
self.to_llvm_type(move_type, &[])
1012-
.unwrap_or_else(|| panic!("{move_type:?} should be available"))
1013-
})
1014-
.collect::<Vec<_>>();
1015-
Some(
1010+
.map(|move_type| self.to_llvm_type(move_type, tyvec))
1011+
.collect();
1012+
llvm_types.map(|types| {
10161013
self.llvm_cx
1017-
.anonymous_struct_type(&llvm_types)
1018-
.as_any_type(),
1019-
)
1014+
.anonymous_struct_type(&types)
1015+
.as_any_type()
1016+
})
10201017
}
10211018
}
10221019
Type::Fun(_, _, _)

crates/move-to-polka/src/stackless/translate.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1984,7 +1984,8 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
19841984
&& ModuleContext::type_has_type_params(&ret_type));
19851985
(arg_types, return_val_is_generic, ret_type)
19861986
};
1987-
let _return_val_is_tuple = matches!(&ret_type, mty::Type::Tuple(ts) if ts.len() > 1);
1987+
let _return_val_is_tuple = !return_val_is_generic
1988+
&& matches!(&ret_type, mty::Type::Tuple(ts) if ts.len() > 1);
19881989

19891990
let typarams = typarams.into_iter().map(|llval| llval.as_any_value());
19901991
let src = src_locals

0 commit comments

Comments
 (0)