Skip to content

Commit b929a50

Browse files
authored
compiler parity for typealias (RustPython#7645)
1 parent f8862e4 commit b929a50

4 files changed

Lines changed: 205 additions & 141 deletions

File tree

Lib/test/test_compile.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1158,7 +1158,6 @@ def foo(x):
11581158
self.assertIn('LOAD_ATTR', instructions)
11591159
self.assertIn('CALL', instructions)
11601160

1161-
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 'LOAD_SMALL_INT' not found in ['RESUME', 'LOAD_CONST', 'RETURN_VALUE']
11621161
def test_folding_type_param(self):
11631162
get_code_fn_cls = lambda x: x.co_consts[0].co_consts[2]
11641163
get_code_type_alias = lambda x: x.co_consts[0].co_consts[3]

crates/codegen/src/compile.rs

Lines changed: 130 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,12 +1249,35 @@ impl Compiler {
12491249

12501250
// Build freevars using dictbytype (FREE scope, offset by cellvars size)
12511251
let mut freevar_cache = IndexSet::default();
1252+
let annotation_free_names: IndexSet<String> = ste
1253+
.annotation_block
1254+
.as_ref()
1255+
.map(|annotation| {
1256+
annotation
1257+
.symbols
1258+
.iter()
1259+
.filter(|(_, s)| {
1260+
s.scope == SymbolScope::Free || s.flags.contains(SymbolFlags::FREE_CLASS)
1261+
})
1262+
.map(|(name, _)| name.clone())
1263+
.collect()
1264+
})
1265+
.unwrap_or_default();
12521266
let mut free_names: Vec<_> = ste
12531267
.symbols
12541268
.iter()
12551269
.filter(|(_, s)| {
12561270
s.scope == SymbolScope::Free || s.flags.contains(SymbolFlags::FREE_CLASS)
12571271
})
1272+
.filter(|(name, symbol)| {
1273+
if !matches!(
1274+
scope_type,
1275+
CompilerScope::Function | CompilerScope::AsyncFunction | CompilerScope::Lambda
1276+
) {
1277+
return true;
1278+
}
1279+
!(annotation_free_names.contains(*name) && symbol.flags.is_empty())
1280+
})
12581281
.map(|(name, _)| name.clone())
12591282
.collect();
12601283
free_names.sort();
@@ -1866,9 +1889,18 @@ impl Compiler {
18661889
let mut parent_idx = stack_size - 2;
18671890
let mut parent = &self.code_stack[parent_idx];
18681891

1869-
// If parent is ast::TypeParams scope, look at grandparent
1870-
// Check if parent is a type params scope by name pattern
1871-
if parent.metadata.name.starts_with("<generic parameters of ") {
1892+
let parent_scope = self
1893+
.symbol_table_stack
1894+
.get(parent_idx)
1895+
.map(|table| table.typ);
1896+
1897+
// CPython skips both generic-parameter scopes and annotation scopes
1898+
// when building qualnames for the contained function/class code object.
1899+
if matches!(
1900+
parent_scope,
1901+
Some(CompilerScope::TypeParams | CompilerScope::Annotation)
1902+
) || parent.metadata.name.starts_with("<generic parameters of ")
1903+
{
18721904
if stack_size == 2 {
18731905
// If we're immediately within the module, qualname is just the name
18741906
return current_obj_name;
@@ -2294,7 +2326,13 @@ impl Compiler {
22942326
NameOp::Name
22952327
}
22962328
}
2297-
SymbolScope::GlobalExplicit => NameOp::Global,
2329+
SymbolScope::GlobalExplicit => {
2330+
if can_see_class_scope {
2331+
NameOp::DictOrGlobals
2332+
} else {
2333+
NameOp::Global
2334+
}
2335+
}
22982336
SymbolScope::Unknown => {
22992337
if module_global_from_nested_scope {
23002338
NameOp::Global
@@ -2797,24 +2835,14 @@ impl Compiler {
27972835
value,
27982836
..
27992837
}) => {
2800-
// let name_string = name.to_string();
28012838
let Some(name) = name.as_name_expr() else {
2802-
// FIXME: is error here?
28032839
return Err(self.error(CodegenErrorType::SyntaxError(
28042840
"type alias expect name".to_owned(),
28052841
)));
28062842
};
28072843
let name_string = name.id.to_string();
28082844

2809-
// For PEP 695 syntax, we need to compile type_params first
2810-
// so that they're available when compiling the value expression
2811-
// Push name first
2812-
self.emit_load_const(ConstantData::Str {
2813-
value: name_string.clone().into(),
2814-
});
2815-
28162845
if let Some(type_params) = type_params {
2817-
// Outer scope for TypeParams
28182846
self.push_symbol_table()?;
28192847
let key = self.symbol_table_stack.len() - 1;
28202848
let lineno = self.get_source_line_number().get().to_u32();
@@ -2830,89 +2858,40 @@ impl Compiler {
28302858
in_async_scope: false,
28312859
};
28322860

2833-
// Compile type params inside the scope
2861+
self.emit_load_const(ConstantData::Str {
2862+
value: name_string.clone().into(),
2863+
});
28342864
self.compile_type_params(type_params)?;
2835-
// Stack: [type_params_tuple]
2836-
2837-
// Inner closure for lazy value evaluation
2838-
self.push_symbol_table()?;
2839-
let inner_key = self.symbol_table_stack.len() - 1;
2840-
self.enter_scope("TypeAlias", CompilerScope::TypeParams, inner_key, lineno)?;
2841-
// Evaluator takes a positional-only format parameter
2842-
self.current_code_info().metadata.argcount = 1;
2843-
self.current_code_info().metadata.posonlyargcount = 1;
2844-
self.current_code_info()
2845-
.metadata
2846-
.varnames
2847-
.insert("format".to_owned());
2848-
self.emit_format_validation()?;
2849-
self.compile_expression(value)?;
2850-
emit!(self, Instruction::ReturnValue);
2851-
let value_code = self.exit_scope();
2852-
self.make_closure(value_code, bytecode::MakeFunctionFlags::new())?;
2853-
// Stack: [type_params_tuple, value_closure]
2854-
2855-
// Swap so unpack_sequence reverse gives correct order
2856-
emit!(self, Instruction::Swap { i: 2 });
2857-
// Stack: [value_closure, type_params_tuple]
2858-
2859-
// Build tuple and return from TypeParams scope
2860-
emit!(self, Instruction::BuildTuple { count: 2 });
2865+
self.compile_typealias_value_closure(&name_string, value)?;
2866+
emit!(self, Instruction::BuildTuple { count: 3 });
2867+
emit!(
2868+
self,
2869+
Instruction::CallIntrinsic1 {
2870+
func: bytecode::IntrinsicFunction1::TypeAlias
2871+
}
2872+
);
28612873
emit!(self, Instruction::ReturnValue);
28622874

28632875
let code = self.exit_scope();
28642876
self.ctx = prev_ctx;
28652877
self.make_closure(code, bytecode::MakeFunctionFlags::new())?;
28662878
emit!(self, Instruction::PushNull);
28672879
emit!(self, Instruction::Call { argc: 0 });
2868-
2869-
// Unpack: (value_closure, type_params_tuple)
2870-
// UnpackSequence reverses → stack: [name, type_params_tuple, value_closure]
2871-
emit!(self, Instruction::UnpackSequence { count: 2 });
28722880
} else {
2873-
// Push None for type_params
2881+
self.emit_load_const(ConstantData::Str {
2882+
value: name_string.clone().into(),
2883+
});
28742884
self.emit_load_const(ConstantData::None);
2875-
// Stack: [name, None]
2876-
2877-
// Create a closure for lazy evaluation of the value
2878-
self.push_symbol_table()?;
2879-
let key = self.symbol_table_stack.len() - 1;
2880-
let lineno = self.get_source_line_number().get().to_u32();
2881-
self.enter_scope("TypeAlias", CompilerScope::TypeParams, key, lineno)?;
2882-
// Evaluator takes a positional-only format parameter
2883-
self.current_code_info().metadata.argcount = 1;
2884-
self.current_code_info().metadata.posonlyargcount = 1;
2885-
self.current_code_info()
2886-
.metadata
2887-
.varnames
2888-
.insert("format".to_owned());
2889-
self.emit_format_validation()?;
2890-
2891-
let prev_ctx = self.ctx;
2892-
self.ctx = CompileContext {
2893-
loop_data: None,
2894-
in_class: prev_ctx.in_class,
2895-
func: FunctionContext::Function,
2896-
in_async_scope: false,
2897-
};
2898-
2899-
self.compile_expression(value)?;
2900-
emit!(self, Instruction::ReturnValue);
2901-
2902-
let code = self.exit_scope();
2903-
self.ctx = prev_ctx;
2904-
self.make_closure(code, bytecode::MakeFunctionFlags::new())?;
2905-
// Stack: [name, None, closure]
2885+
self.compile_typealias_value_closure(&name_string, value)?;
2886+
emit!(self, Instruction::BuildTuple { count: 3 });
2887+
emit!(
2888+
self,
2889+
Instruction::CallIntrinsic1 {
2890+
func: bytecode::IntrinsicFunction1::TypeAlias
2891+
}
2892+
);
29062893
}
29072894

2908-
// Build tuple of 3 elements and call intrinsic
2909-
emit!(self, Instruction::BuildTuple { count: 3 });
2910-
emit!(
2911-
self,
2912-
Instruction::CallIntrinsic1 {
2913-
func: bytecode::IntrinsicFunction1::TypeAlias
2914-
}
2915-
);
29162895
self.store_name(&name_string)?;
29172896
}
29182897
ast::Stmt::IpyEscapeCommand(_) => todo!(),
@@ -3015,6 +2994,10 @@ impl Compiler {
30152994
name: &str,
30162995
allow_starred: bool,
30172996
) -> CompileResult<()> {
2997+
self.emit_load_const(ConstantData::Tuple {
2998+
elements: vec![ConstantData::Integer { value: 1.into() }],
2999+
});
3000+
30183001
// Push the next symbol table onto the stack
30193002
self.push_symbol_table()?;
30203003

@@ -3023,11 +3006,8 @@ impl Compiler {
30233006
let lineno = self.get_source_line_number().get().to_u32();
30243007

30253008
// Enter scope with the type parameter name
3026-
self.enter_scope(name, CompilerScope::TypeParams, key, lineno)?;
3009+
self.enter_scope(name, CompilerScope::Annotation, key, lineno)?;
30273010

3028-
// Evaluator takes a positional-only format parameter
3029-
self.current_code_info().metadata.argcount = 1;
3030-
self.current_code_info().metadata.posonlyargcount = 1;
30313011
self.current_code_info()
30323012
.metadata
30333013
.varnames
@@ -3061,8 +3041,50 @@ impl Compiler {
30613041
let code = self.exit_scope();
30623042
self.ctx = prev_ctx;
30633043

3064-
// Create closure for lazy evaluation
3065-
self.make_closure(code, bytecode::MakeFunctionFlags::new())?;
3044+
self.make_closure(
3045+
code,
3046+
bytecode::MakeFunctionFlags::from([bytecode::MakeFunctionFlag::Defaults]),
3047+
)?;
3048+
3049+
Ok(())
3050+
}
3051+
3052+
fn compile_typealias_value_closure(
3053+
&mut self,
3054+
alias_name: &str,
3055+
value: &ast::Expr,
3056+
) -> CompileResult<()> {
3057+
self.emit_load_const(ConstantData::Tuple {
3058+
elements: vec![ConstantData::Integer { value: 1.into() }],
3059+
});
3060+
3061+
self.push_symbol_table()?;
3062+
let key = self.symbol_table_stack.len() - 1;
3063+
let lineno = self.get_source_line_number().get().to_u32();
3064+
self.enter_scope(alias_name, CompilerScope::Annotation, key, lineno)?;
3065+
self.current_code_info()
3066+
.metadata
3067+
.varnames
3068+
.insert(".format".to_owned());
3069+
self.emit_format_validation()?;
3070+
3071+
let prev_ctx = self.ctx;
3072+
self.ctx = CompileContext {
3073+
loop_data: None,
3074+
in_class: prev_ctx.in_class,
3075+
func: FunctionContext::Function,
3076+
in_async_scope: false,
3077+
};
3078+
3079+
self.compile_expression(value)?;
3080+
emit!(self, Instruction::ReturnValue);
3081+
3082+
let code = self.exit_scope();
3083+
self.ctx = prev_ctx;
3084+
self.make_closure(
3085+
code,
3086+
bytecode::MakeFunctionFlags::from([bytecode::MakeFunctionFlag::Defaults]),
3087+
)?;
30663088

30673089
Ok(())
30683090
}
@@ -3084,12 +3106,7 @@ impl Compiler {
30843106
});
30853107

30863108
if let Some(expr) = &bound {
3087-
let scope_name = if expr.is_tuple_expr() {
3088-
format!("<TypeVar constraint of {name}>")
3089-
} else {
3090-
format!("<TypeVar bound of {name}>")
3091-
};
3092-
self.compile_type_param_bound_or_default(expr, &scope_name, false)?;
3109+
self.compile_type_param_bound_or_default(expr, name.as_str(), false)?;
30933110

30943111
let intrinsic = if expr.is_tuple_expr() {
30953112
bytecode::IntrinsicFunction2::TypeVarWithConstraint
@@ -3107,8 +3124,11 @@ impl Compiler {
31073124
}
31083125

31093126
if let Some(default_expr) = default {
3110-
let scope_name = format!("<TypeVar default of {name}>");
3111-
self.compile_type_param_bound_or_default(default_expr, &scope_name, false)?;
3127+
self.compile_type_param_bound_or_default(
3128+
default_expr,
3129+
name.as_str(),
3130+
false,
3131+
)?;
31123132
emit!(
31133133
self,
31143134
Instruction::CallIntrinsic2 {
@@ -3132,8 +3152,11 @@ impl Compiler {
31323152
);
31333153

31343154
if let Some(default_expr) = default {
3135-
let scope_name = format!("<ParamSpec default of {name}>");
3136-
self.compile_type_param_bound_or_default(default_expr, &scope_name, false)?;
3155+
self.compile_type_param_bound_or_default(
3156+
default_expr,
3157+
name.as_str(),
3158+
false,
3159+
)?;
31373160
emit!(
31383161
self,
31393162
Instruction::CallIntrinsic2 {
@@ -3160,8 +3183,11 @@ impl Compiler {
31603183

31613184
if let Some(default_expr) = default {
31623185
// TypeVarTuple allows starred expressions
3163-
let scope_name = format!("<TypeVarTuple default of {name}>");
3164-
self.compile_type_param_bound_or_default(default_expr, &scope_name, true)?;
3186+
self.compile_type_param_bound_or_default(
3187+
default_expr,
3188+
name.as_str(),
3189+
true,
3190+
)?;
31653191
emit!(
31663192
self,
31673193
Instruction::CallIntrinsic2 {
@@ -4560,7 +4586,7 @@ impl Compiler {
45604586
self.current_code_info()
45614587
.metadata
45624588
.varnames
4563-
.insert("format".to_owned());
4589+
.insert(".format".to_owned());
45644590

45654591
// Emit format validation: if format > VALUE_WITH_FAKE_GLOBALS: raise NotImplementedError
45664592
self.emit_format_validation()?;

0 commit comments

Comments
 (0)