From fbc9e5031d1ef1a8bd6572485f099ce918110aa2 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 29 Jun 2025 04:10:51 +0900 Subject: [PATCH] Fix TypeParams, TypeAlias compile --- compiler/codegen/src/compile.rs | 26 ++++++++++++++++++++++---- vm/src/frame.rs | 16 ++++++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/compiler/codegen/src/compile.rs b/compiler/codegen/src/compile.rs index 2e7e5a4ad5..71b94cdb96 100644 --- a/compiler/codegen/src/compile.rs +++ b/compiler/codegen/src/compile.rs @@ -1042,14 +1042,32 @@ impl Compiler<'_> { ))); }; let name_string = name.id.to_string(); - if type_params.is_some() { - self.push_symbol_table(); - } - self.compile_expression(value)?; + + // For PEP 695 syntax, we need to compile type_params first + // so that they're available when compiling the value expression if let Some(type_params) = type_params { + self.push_symbol_table(); + + // Compile type params first to define T1, T2, etc. self.compile_type_params(type_params)?; + // Stack now has type_params tuple at top + + // Compile value expression (can now see T1, T2) + self.compile_expression(value)?; + // Stack: [type_params_tuple, value] + + // We need [value, type_params_tuple] for TypeAlias instruction + emit!(self, Instruction::Rotate2); + self.pop_symbol_table(); + } else { + // No type params - push value first, then None (not empty tuple) + self.compile_expression(value)?; + // Push None for type_params (matching CPython) + self.emit_load_const(ConstantData::None); } + + // Push name last self.emit_load_const(ConstantData::Str { value: name_string.clone().into(), }); diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 7f10a348f2..3a02d582a1 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -1266,10 +1266,18 @@ impl ExecutingFrame<'_> { } bytecode::Instruction::TypeAlias => { let name = self.pop_value(); - let type_params: PyTupleRef = self - .pop_value() - .downcast() - .map_err(|_| vm.new_type_error("Type params must be a tuple."))?; + let type_params_obj = self.pop_value(); + + // CPython allows None or tuple for type_params + let type_params: PyTupleRef = if vm.is_none(&type_params_obj) { + // If None, use empty tuple (matching CPython's behavior) + vm.ctx.empty_tuple.clone() + } else { + type_params_obj + .downcast() + .map_err(|_| vm.new_type_error("Type params must be a tuple."))? + }; + let value = self.pop_value(); let type_alias = typing::TypeAliasType::new(name, type_params, value); self.push_value(type_alias.into_ref(&vm.ctx).into());