1#![deny(clippy::cast_possible_truncation)]
11
12use crate::{
13 IndexMap, IndexSet, ToPythonName,
14 error::{CodegenError, CodegenErrorType, InternalError, PatternUnreachableReason},
15 ir::{self, BlockIdx},
16 symboltable::{self, CompilerScope, Symbol, SymbolFlags, SymbolScope, SymbolTable},
17 unparse::UnparseExpr,
18};
19use alloc::borrow::Cow;
20use itertools::Itertools;
21use malachite_bigint::BigInt;
22use num_complex::Complex;
23use num_traits::{Num, ToPrimitive};
24use ruff_python_ast as ast;
25use ruff_text_size::{Ranged, TextRange, TextSize};
26use rustpython_compiler_core::{
27 Mode, OneIndexed, PositionEncoding, SourceFile, SourceLocation,
28 bytecode::{
29 self, AnyInstruction, Arg as OpArgMarker, BinaryOperator, BuildSliceArgCount, CodeObject,
30 ComparisonOperator, ConstantData, ConvertValueOparg, Instruction, IntrinsicFunction1,
31 Invert, LoadAttr, LoadSuperAttr, OpArg, OpArgType, PseudoInstruction, SpecialMethod,
32 UnpackExArgs, oparg,
33 },
34};
35use rustpython_wtf8::Wtf8Buf;
36
37trait ExprExt {
39 fn is_constant(&self) -> bool;
41
42 fn is_constant_slice(&self) -> bool;
44
45 fn should_use_slice_optimization(&self) -> bool;
47}
48
49impl ExprExt for ast::Expr {
50 fn is_constant(&self) -> bool {
51 matches!(
52 self,
53 ast::Expr::NumberLiteral(_)
54 | ast::Expr::StringLiteral(_)
55 | ast::Expr::BytesLiteral(_)
56 | ast::Expr::NoneLiteral(_)
57 | ast::Expr::BooleanLiteral(_)
58 | ast::Expr::EllipsisLiteral(_)
59 ) || matches!(self, ast::Expr::Tuple(ast::ExprTuple { elts, .. }) if elts.iter().all(ExprExt::is_constant))
60 }
61
62 fn is_constant_slice(&self) -> bool {
63 match self {
64 ast::Expr::Slice(s) => {
65 let lower_const =
66 s.lower.is_none() || s.lower.as_deref().is_some_and(|e| e.is_constant());
67 let upper_const =
68 s.upper.is_none() || s.upper.as_deref().is_some_and(|e| e.is_constant());
69 let step_const =
70 s.step.is_none() || s.step.as_deref().is_some_and(|e| e.is_constant());
71 lower_const && upper_const && step_const
72 }
73 _ => false,
74 }
75 }
76
77 fn should_use_slice_optimization(&self) -> bool {
78 !self.is_constant_slice() && matches!(self, ast::Expr::Slice(s) if s.step.is_none())
79 }
80}
81
82const MAXBLOCKS: usize = 20;
83
84#[derive(Debug, Clone, Copy)]
85pub enum FBlockType {
86 WhileLoop,
87 ForLoop,
88 TryExcept,
89 FinallyTry,
90 FinallyEnd,
91 With,
92 AsyncWith,
93 HandlerCleanup,
94 PopValue,
95 ExceptionHandler,
96 ExceptionGroupHandler,
97 AsyncComprehensionGenerator,
98 StopIteration,
99}
100
101#[derive(Debug, Clone)]
104pub enum FBlockDatum {
105 None,
106 FinallyBody(Vec<ast::Stmt>),
108 ExceptionName(String),
110}
111
112#[derive(Debug, Clone)]
114enum SuperCallType<'a> {
115 TwoArg {
117 class_arg: &'a ast::Expr,
118 self_arg: &'a ast::Expr,
119 },
120 ZeroArg,
122}
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq)]
125enum BuiltinGeneratorCallKind {
126 Tuple,
127 List,
128 Set,
129 All,
130 Any,
131}
132
133#[derive(Debug, Clone)]
134pub struct FBlockInfo {
135 pub fb_type: FBlockType,
136 pub fb_block: BlockIdx,
137 pub fb_exit: BlockIdx,
138 pub fb_datum: FBlockDatum,
140}
141
142pub(crate) type InternalResult<T> = Result<T, InternalError>;
143type CompileResult<T> = Result<T, CodegenError>;
144
145#[derive(PartialEq, Eq, Clone, Copy)]
146enum NameUsage {
147 Load,
148 Store,
149 Delete,
150}
151struct Compiler {
153 code_stack: Vec<ir::CodeInfo>,
154 symbol_table_stack: Vec<SymbolTable>,
155 source_file: SourceFile,
156 current_source_range: TextRange,
158 done_with_future_stmts: DoneWithFuture,
159 future_annotations: bool,
160 ctx: CompileContext,
161 opts: CompileOpts,
162 in_annotation: bool,
163 interactive: bool,
166 do_not_emit_bytecode: u32,
170}
171
172#[derive(Clone, Copy)]
173enum DoneWithFuture {
174 No,
175 DoneWithDoc,
176 Yes,
177}
178
179#[derive(Clone, Copy, Debug)]
180pub struct CompileOpts {
181 pub optimize: u8,
184 pub debug_ranges: bool,
186}
187
188impl Default for CompileOpts {
189 fn default() -> Self {
190 Self {
191 optimize: 0,
192 debug_ranges: true,
193 }
194 }
195}
196
197#[derive(Debug, Clone, Copy)]
198struct CompileContext {
199 loop_data: Option<(BlockIdx, BlockIdx)>,
200 in_class: bool,
201 func: FunctionContext,
202 in_async_scope: bool,
204}
205
206#[derive(Debug, Clone, Copy, PartialEq)]
207enum FunctionContext {
208 NoFunction,
209 Function,
210 AsyncFunction,
211}
212
213impl CompileContext {
214 fn in_func(self) -> bool {
215 self.func != FunctionContext::NoFunction
216 }
217}
218
219struct FormatSegment {
221 literal: String,
222 conversion: Option<oparg::ConvertValueOparg>,
223}
224
225#[derive(Debug, Clone, Copy, PartialEq)]
226enum ComprehensionType {
227 Generator,
228 List,
229 Set,
230 Dict,
231}
232
233fn validate_duplicate_params(params: &ast::Parameters) -> Result<(), CodegenErrorType> {
234 let mut seen_params = IndexSet::default();
235 for param in params {
236 let param_name = param.name().as_str();
237 if !seen_params.insert(param_name) {
238 return Err(CodegenErrorType::SyntaxError(format!(
239 r#"Duplicate parameter "{param_name}""#
240 )));
241 }
242 }
243
244 Ok(())
245}
246
247pub fn compile_top(
249 ast: ruff_python_ast::Mod,
250 source_file: SourceFile,
251 mode: Mode,
252 opts: CompileOpts,
253) -> CompileResult<CodeObject> {
254 match ast {
255 ruff_python_ast::Mod::Module(module) => match mode {
256 Mode::Exec | Mode::Eval => compile_program(&module, source_file, opts),
257 Mode::Single => compile_program_single(&module, source_file, opts),
258 Mode::BlockExpr => compile_block_expression(&module, source_file, opts),
259 },
260 ruff_python_ast::Mod::Expression(expr) => compile_expression(&expr, source_file, opts),
261 }
262}
263
264pub fn compile_program(
266 ast: &ast::ModModule,
267 source_file: SourceFile,
268 opts: CompileOpts,
269) -> CompileResult<CodeObject> {
270 let symbol_table = SymbolTable::scan_program(ast, source_file.clone())
271 .map_err(|e| e.into_codegen_error(source_file.name().to_owned()))?;
272 let mut compiler = Compiler::new(opts, source_file, "<module>".to_owned());
273 compiler.compile_program(ast, symbol_table)?;
274 let code = compiler.exit_scope();
275 trace!("Compilation completed: {code:?}");
276 Ok(code)
277}
278
279pub fn compile_program_single(
281 ast: &ast::ModModule,
282 source_file: SourceFile,
283 opts: CompileOpts,
284) -> CompileResult<CodeObject> {
285 let symbol_table = SymbolTable::scan_program(ast, source_file.clone())
286 .map_err(|e| e.into_codegen_error(source_file.name().to_owned()))?;
287 let mut compiler = Compiler::new(opts, source_file, "<module>".to_owned());
288 compiler.compile_program_single(&ast.body, symbol_table)?;
289 let code = compiler.exit_scope();
290 trace!("Compilation completed: {code:?}");
291 Ok(code)
292}
293
294pub fn compile_block_expression(
295 ast: &ast::ModModule,
296 source_file: SourceFile,
297 opts: CompileOpts,
298) -> CompileResult<CodeObject> {
299 let symbol_table = SymbolTable::scan_program(ast, source_file.clone())
300 .map_err(|e| e.into_codegen_error(source_file.name().to_owned()))?;
301 let mut compiler = Compiler::new(opts, source_file, "<module>".to_owned());
302 compiler.compile_block_expr(&ast.body, symbol_table)?;
303 let code = compiler.exit_scope();
304 trace!("Compilation completed: {code:?}");
305 Ok(code)
306}
307
308pub fn compile_expression(
309 ast: &ast::ModExpression,
310 source_file: SourceFile,
311 opts: CompileOpts,
312) -> CompileResult<CodeObject> {
313 let symbol_table = SymbolTable::scan_expr(ast, source_file.clone())
314 .map_err(|e| e.into_codegen_error(source_file.name().to_owned()))?;
315 let mut compiler = Compiler::new(opts, source_file, "<module>".to_owned());
316 compiler.compile_eval(ast, symbol_table)?;
317 let code = compiler.exit_scope();
318 Ok(code)
319}
320
321macro_rules! emit {
322 ($c:expr, $enum:ident :: $op:ident { $arg:ident $(,)? } $(,)?) => {
324 $c.emit_arg($arg, |x| $enum::$op { $arg: x })
325 };
326
327 ($c:expr, $enum:ident :: $op:ident { $arg:ident : $arg_val:expr $(,)? } $(,)?) => {
329 $c.emit_arg($arg_val, |x| $enum::$op { $arg: x })
330 };
331
332 ($c:expr, $enum:ident :: $op:ident($arg_val:expr $(,)? ) $(,)?) => {
334 panic!("No instruction should be defined as `Instruction::Foo(value)` use `Instruction::Foo { x: value }` instead")
335 };
336
337 ($c:expr, $enum:ident :: $op:ident $(,)?) => {
339 $c.emit_no_arg($enum::$op)
340 };
341}
342
343fn eprint_location(zelf: &Compiler) {
344 let start = zelf
345 .source_file
346 .to_source_code()
347 .source_location(zelf.current_source_range.start(), PositionEncoding::Utf8);
348 let end = zelf
349 .source_file
350 .to_source_code()
351 .source_location(zelf.current_source_range.end(), PositionEncoding::Utf8);
352 eprintln!(
353 "LOCATION: {} from {}:{} to {}:{}",
354 zelf.source_file.name(),
355 start.line,
356 start.character_offset,
357 end.line,
358 end.character_offset
359 );
360}
361
362#[track_caller]
364fn unwrap_internal<T>(zelf: &Compiler, r: InternalResult<T>) -> T {
365 if let Err(ref r_err) = r {
366 eprintln!("=== CODEGEN PANIC INFO ===");
367 eprintln!("This IS an internal error: {r_err}");
368 eprint_location(zelf);
369 eprintln!("=== END PANIC INFO ===");
370 }
371 r.unwrap()
372}
373
374fn compiler_unwrap_option<T>(zelf: &Compiler, o: Option<T>) -> T {
375 if o.is_none() {
376 eprintln!("=== CODEGEN PANIC INFO ===");
377 eprintln!("This IS an internal error, an option was unwrapped during codegen");
378 eprint_location(zelf);
379 eprintln!("=== END PANIC INFO ===");
380 }
381 o.unwrap()
382}
383
384#[derive(Clone)]
396pub struct PatternContext {
397 pub stores: Vec<String>,
399 pub allow_irrefutable: bool,
401 pub fail_pop: Vec<BlockIdx>,
403 pub on_top: usize,
405}
406
407impl Default for PatternContext {
408 fn default() -> Self {
409 Self::new()
410 }
411}
412
413impl PatternContext {
414 pub const fn new() -> Self {
415 Self {
416 stores: Vec::new(),
417 allow_irrefutable: false,
418 fail_pop: Vec::new(),
419 on_top: 0,
420 }
421 }
422
423 pub fn fail_pop_size(&self) -> usize {
424 self.fail_pop.len()
425 }
426}
427
428enum JumpOp {
429 Jump,
430 PopJumpIfFalse,
431}
432
433#[derive(Debug, Clone, Copy, PartialEq)]
435enum CollectionType {
436 Tuple,
437 List,
438 Set,
439}
440
441impl Compiler {
442 fn new(opts: CompileOpts, source_file: SourceFile, code_name: String) -> Self {
443 let module_code = ir::CodeInfo {
444 flags: bytecode::CodeFlags::NEWLOCALS,
445 source_path: source_file.name().to_owned(),
446 private: None,
447 blocks: vec![ir::Block::default()],
448 current_block: BlockIdx::new(0),
449 metadata: ir::CodeUnitMetadata {
450 name: code_name.clone(),
451 qualname: Some(code_name),
452 consts: IndexSet::default(),
453 names: IndexSet::default(),
454 varnames: IndexSet::default(),
455 cellvars: IndexSet::default(),
456 freevars: IndexSet::default(),
457 fast_hidden: IndexMap::default(),
458 argcount: 0,
459 posonlyargcount: 0,
460 kwonlyargcount: 0,
461 firstlineno: OneIndexed::MIN,
462 },
463 static_attributes: None,
464 in_inlined_comp: false,
465 fblock: Vec::with_capacity(MAXBLOCKS),
466 symbol_table_index: 0, in_conditional_block: 0,
468 next_conditional_annotation_index: 0,
469 };
470 Self {
471 code_stack: vec![module_code],
472 symbol_table_stack: Vec::new(),
473 source_file,
474 current_source_range: TextRange::default(),
476 done_with_future_stmts: DoneWithFuture::No,
477 future_annotations: false,
478 ctx: CompileContext {
479 loop_data: None,
480 in_class: false,
481 func: FunctionContext::NoFunction,
482 in_async_scope: false,
483 },
484 opts,
485 in_annotation: false,
486 interactive: false,
487 do_not_emit_bytecode: 0,
488 }
489 }
490
491 fn compile_slice_two_parts(&mut self, s: &ast::ExprSlice) -> CompileResult<()> {
494 if let Some(lower) = &s.lower {
496 self.compile_expression(lower)?;
497 } else {
498 self.emit_load_const(ConstantData::None);
499 }
500
501 if let Some(upper) = &s.upper {
503 self.compile_expression(upper)?;
504 } else {
505 self.emit_load_const(ConstantData::None);
506 }
507
508 Ok(())
509 }
510 fn compile_subscript(
513 &mut self,
514 value: &ast::Expr,
515 slice: &ast::Expr,
516 ctx: ast::ExprContext,
517 ) -> CompileResult<()> {
518 let subscript_range = self.current_source_range;
520
521 self.compile_expression(value)?;
523
524 let use_slice_opt = matches!(ctx, ast::ExprContext::Load | ast::ExprContext::Store)
526 && slice.should_use_slice_optimization();
527 if use_slice_opt {
528 match slice {
529 ast::Expr::Slice(s) => self.compile_slice_two_parts(s)?,
530 _ => unreachable!(
531 "should_use_slice_optimization should only return true for ast::Expr::Slice"
532 ),
533 };
534 } else {
535 self.compile_expression(slice)?;
537 }
538
539 self.set_source_range(subscript_range);
541
542 match (use_slice_opt, ctx) {
543 (true, ast::ExprContext::Load) => emit!(self, Instruction::BinarySlice),
544 (true, ast::ExprContext::Store) => emit!(self, Instruction::StoreSlice),
545 (true, _) => unreachable!(),
546 (false, ast::ExprContext::Load) => emit!(
547 self,
548 Instruction::BinaryOp {
549 op: BinaryOperator::Subscr
550 }
551 ),
552 (false, ast::ExprContext::Store) => emit!(self, Instruction::StoreSubscr),
553 (false, ast::ExprContext::Del) => emit!(self, Instruction::DeleteSubscr),
554 (false, ast::ExprContext::Invalid) => {
555 return Err(self.error(CodegenErrorType::SyntaxError(
556 "Invalid expression context".to_owned(),
557 )));
558 }
559 }
560
561 Ok(())
562 }
563
564 fn starunpack_helper(
573 &mut self,
574 elts: &[ast::Expr],
575 pushed: u32,
576 collection_type: CollectionType,
577 ) -> CompileResult<()> {
578 let n = elts.len().to_u32();
579 let seen_star = elts.iter().any(|e| matches!(e, ast::Expr::Starred(_)));
580
581 let big = match collection_type {
583 CollectionType::Set => n > 8,
584 _ => n > 4,
585 };
586
587 if !seen_star
589 && pushed == 0
590 && n >= 3
591 && elts.iter().all(|e| e.is_constant())
592 && let Some(folded) = self.try_fold_constant_collection(elts)?
593 {
594 match collection_type {
595 CollectionType::Tuple => {
596 self.emit_load_const(folded);
597 }
598 CollectionType::List => {
599 emit!(self, Instruction::BuildList { count: 0 });
600 self.emit_load_const(folded);
601 emit!(self, Instruction::ListExtend { i: 1 });
602 }
603 CollectionType::Set => {
604 emit!(self, Instruction::BuildSet { count: 0 });
605 self.emit_load_const(folded);
606 emit!(self, Instruction::SetUpdate { i: 1 });
607 }
608 }
609 return Ok(());
610 }
611
612 if !seen_star && !big {
614 for elt in elts {
615 self.compile_expression(elt)?;
616 }
617 let total_size = n + pushed;
618 match collection_type {
619 CollectionType::List => {
620 emit!(self, Instruction::BuildList { count: total_size });
621 }
622 CollectionType::Set => {
623 emit!(self, Instruction::BuildSet { count: total_size });
624 }
625 CollectionType::Tuple => {
626 emit!(self, Instruction::BuildTuple { count: total_size });
627 }
628 }
629 return Ok(());
630 }
631
632 let mut sequence_built = false;
634 let mut i = 0u32;
635
636 for elt in elts.iter() {
637 if let ast::Expr::Starred(ast::ExprStarred { value, .. }) = elt {
638 if !sequence_built {
640 match collection_type {
641 CollectionType::List => {
642 emit!(self, Instruction::BuildList { count: i + pushed });
643 }
644 CollectionType::Set => {
645 emit!(self, Instruction::BuildSet { count: i + pushed });
646 }
647 CollectionType::Tuple => {
648 emit!(self, Instruction::BuildList { count: i + pushed });
649 }
650 }
651 sequence_built = true;
652 }
653
654 self.compile_expression(value)?;
656 match collection_type {
657 CollectionType::List => {
658 emit!(self, Instruction::ListExtend { i: 1 });
659 }
660 CollectionType::Set => {
661 emit!(self, Instruction::SetUpdate { i: 1 });
662 }
663 CollectionType::Tuple => {
664 emit!(self, Instruction::ListExtend { i: 1 });
665 }
666 }
667 } else {
668 self.compile_expression(elt)?;
670
671 if sequence_built {
672 match collection_type {
674 CollectionType::List => {
675 emit!(self, Instruction::ListAppend { i: 1 });
676 }
677 CollectionType::Set => {
678 emit!(self, Instruction::SetAdd { i: 1 });
679 }
680 CollectionType::Tuple => {
681 emit!(self, Instruction::ListAppend { i: 1 });
682 }
683 }
684 } else {
685 i += 1;
687 }
688 }
689 }
690
691 if !sequence_built {
693 match collection_type {
694 CollectionType::List => {
695 emit!(self, Instruction::BuildList { count: i + pushed });
696 }
697 CollectionType::Set => {
698 emit!(self, Instruction::BuildSet { count: i + pushed });
699 }
700 CollectionType::Tuple => {
701 emit!(self, Instruction::BuildTuple { count: i + pushed });
702 }
703 }
704 } else if collection_type == CollectionType::Tuple {
705 emit!(
707 self,
708 Instruction::CallIntrinsic1 {
709 func: IntrinsicFunction1::ListToTuple
710 }
711 );
712 }
713
714 Ok(())
715 }
716
717 fn error(&mut self, error: CodegenErrorType) -> CodegenError {
718 self.error_ranged(error, self.current_source_range)
719 }
720
721 fn error_ranged(&mut self, error: CodegenErrorType, range: TextRange) -> CodegenError {
722 let location = self
723 .source_file
724 .to_source_code()
725 .source_location(range.start(), PositionEncoding::Utf8);
726 CodegenError {
727 error,
728 location: Some(location),
729 source_path: self.source_file.name().to_owned(),
730 }
731 }
732
733 fn current_symbol_table(&self) -> &SymbolTable {
735 self.symbol_table_stack
736 .last()
737 .expect("symbol_table_stack is empty! This is a compiler bug.")
738 }
739
740 fn is_name_imported(&self, name: &str) -> bool {
742 let current = self.current_symbol_table();
743 if let Some(sym) = current.symbols.get(name) {
744 if sym.flags.contains(SymbolFlags::IMPORTED) {
745 return !matches!(
748 current.typ,
749 CompilerScope::Function | CompilerScope::AsyncFunction | CompilerScope::Lambda
750 );
751 }
752 if sym.scope == SymbolScope::Local {
753 return false;
754 }
755 }
756 self.symbol_table_stack.iter().rev().skip(1).any(|table| {
758 table
759 .symbols
760 .get(name)
761 .is_some_and(|sym| sym.flags.contains(SymbolFlags::IMPORTED))
762 })
763 }
764
765 fn get_free_var_index(&mut self, name: &str) -> CompileResult<oparg::VarNum> {
768 let info = self.code_stack.last_mut().unwrap();
769 let idx = info
770 .metadata
771 .freevars
772 .get_index_of(name)
773 .unwrap_or_else(|| info.metadata.freevars.insert_full(name.to_owned()).0);
774 Ok((idx + info.metadata.cellvars.len()).to_u32().into())
775 }
776
777 fn get_cell_var_index(&mut self, name: &str) -> CompileResult<oparg::VarNum> {
780 let info = self.code_stack.last_mut().unwrap();
781 let idx = info
782 .metadata
783 .cellvars
784 .get_index_of(name)
785 .unwrap_or_else(|| info.metadata.cellvars.insert_full(name.to_owned()).0);
786 Ok(idx.to_u32().into())
787 }
788
789 fn get_local_var_index(&mut self, name: &str) -> CompileResult<oparg::VarNum> {
791 let info = self.code_stack.last_mut().unwrap();
792 let idx = info
793 .metadata
794 .varnames
795 .get_index_of(name)
796 .unwrap_or_else(|| info.metadata.varnames.insert_full(name.to_owned()).0);
797 Ok(idx.to_u32().into())
798 }
799
800 fn get_global_name_index(&mut self, name: &str) -> u32 {
802 let info = self.code_stack.last_mut().unwrap();
803 let idx = info
804 .metadata
805 .names
806 .get_index_of(name)
807 .unwrap_or_else(|| info.metadata.names.insert_full(name.to_owned()).0);
808 idx.to_u32()
809 }
810
811 fn push_symbol_table(&mut self) -> CompileResult<&SymbolTable> {
813 let current_table = self
815 .symbol_table_stack
816 .last_mut()
817 .expect("no current symbol table");
818
819 if current_table.next_sub_table >= current_table.sub_tables.len() {
820 let name = current_table.name.clone();
821 let typ = current_table.typ;
822 return Err(self.error(CodegenErrorType::SyntaxError(format!(
823 "no symbol table available in {} (type: {:?})",
824 name, typ
825 ))));
826 }
827
828 let idx = current_table.next_sub_table;
829 current_table.next_sub_table += 1;
830 let table = current_table.sub_tables[idx].clone();
831
832 self.symbol_table_stack.push(table);
834 Ok(self.current_symbol_table())
835 }
836
837 fn push_annotation_symbol_table(&mut self) -> bool {
841 let current_table = self
842 .symbol_table_stack
843 .last_mut()
844 .expect("no current symbol table");
845
846 let next_idx = current_table.next_sub_table;
848 if next_idx >= current_table.sub_tables.len() {
849 return false;
850 }
851
852 let next_table = &mut current_table.sub_tables[next_idx];
853 if let Some(annotation_block) = next_table.annotation_block.take() {
854 self.symbol_table_stack.push(*annotation_block);
855 true
856 } else {
857 false
858 }
859 }
860
861 fn push_current_annotation_symbol_table(&mut self) -> bool {
864 let current_table = self
865 .symbol_table_stack
866 .last_mut()
867 .expect("no current symbol table");
868
869 if let Some(annotation_block) = current_table.annotation_block.take() {
871 self.symbol_table_stack.push(*annotation_block);
872 true
873 } else {
874 false
875 }
876 }
877
878 fn pop_annotation_symbol_table(&mut self) {
880 let annotation_table = self.symbol_table_stack.pop().expect("compiler bug");
881 let current_table = self
882 .symbol_table_stack
883 .last_mut()
884 .expect("no current symbol table");
885
886 let next_idx = current_table.next_sub_table;
888 if next_idx < current_table.sub_tables.len() {
889 current_table.sub_tables[next_idx].annotation_block = Some(Box::new(annotation_table));
890 }
891 }
892
893 fn pop_symbol_table(&mut self) -> SymbolTable {
895 self.symbol_table_stack.pop().expect("compiler bug")
896 }
897
898 fn can_optimize_super_call<'a>(
901 &self,
902 value: &'a ast::Expr,
903 attr: &str,
904 ) -> Option<SuperCallType<'a>> {
905 let ast::Expr::Call(ast::ExprCall {
907 func, arguments, ..
908 }) = value
909 else {
910 return None;
911 };
912
913 let ast::Expr::Name(ast::ExprName { id, .. }) = func.as_ref() else {
915 return None;
916 };
917 if id.as_str() != "super" {
918 return None;
919 }
920
921 if attr == "__class__" {
923 return None;
924 }
925
926 if !arguments.keywords.is_empty() {
928 return None;
929 }
930
931 if !self.ctx.in_func() {
933 return None;
934 }
935
936 let table = self.current_symbol_table();
938 if let Some(symbol) = table.lookup("super")
939 && symbol.scope != SymbolScope::GlobalImplicit
940 {
941 return None;
942 }
943 if let Some(top_table) = self.symbol_table_stack.first()
946 && let Some(sym) = top_table.lookup("super")
947 && sym.scope != SymbolScope::GlobalImplicit
948 {
949 return None;
950 }
951
952 let args = &arguments.args;
954
955 if args.iter().any(|arg| matches!(arg, ast::Expr::Starred(_))) {
957 return None;
958 }
959
960 match args.len() {
961 2 => {
962 Some(SuperCallType::TwoArg {
964 class_arg: &args[0],
965 self_arg: &args[1],
966 })
967 }
968 0 => {
969 let info = self.code_stack.last()?;
972 if info.metadata.argcount == 0 && info.metadata.posonlyargcount == 0 {
973 return None;
974 }
975
976 if let Some(symbol) = table.lookup("__class__") {
979 if symbol.scope != SymbolScope::Free
980 && !symbol.flags.contains(SymbolFlags::FREE_CLASS)
981 {
982 return None;
983 }
984 } else {
985 return None;
987 }
988
989 Some(SuperCallType::ZeroArg)
990 }
991 _ => None, }
993 }
994
995 fn load_args_for_super(&mut self, super_type: &SuperCallType<'_>) -> CompileResult<()> {
998 self.compile_name("super", NameUsage::Load)?;
1000
1001 match super_type {
1002 SuperCallType::TwoArg {
1003 class_arg,
1004 self_arg,
1005 } => {
1006 self.compile_expression(class_arg)?;
1008 self.compile_expression(self_arg)?;
1009 }
1010 SuperCallType::ZeroArg => {
1011 let scope = self.get_ref_type("__class__").map_err(|e| self.error(e))?;
1014 let idx = match scope {
1015 SymbolScope::Cell => self.get_cell_var_index("__class__")?,
1016 SymbolScope::Free => self.get_free_var_index("__class__")?,
1017 _ => {
1018 return Err(self.error(CodegenErrorType::SyntaxError(
1019 "super(): __class__ cell not found".to_owned(),
1020 )));
1021 }
1022 };
1023 emit!(self, Instruction::LoadDeref { i: idx });
1024
1025 let first_param = {
1029 let info = self.code_stack.last().unwrap();
1030 info.metadata.varnames.first().cloned()
1031 };
1032 let first_param = first_param.ok_or_else(|| {
1033 self.error(CodegenErrorType::SyntaxError(
1034 "super(): no arguments and no first parameter".to_owned(),
1035 ))
1036 })?;
1037 self.compile_name(&first_param, NameUsage::Load)?;
1038 }
1039 }
1040 Ok(())
1041 }
1042
1043 fn is_inlined_comprehension_context(&self, comprehension_type: ComprehensionType) -> bool {
1048 if comprehension_type == ComprehensionType::Generator {
1049 return false;
1050 }
1051 if !self.ctx.in_func() {
1052 return false;
1053 }
1054 self.symbol_table_stack
1055 .last()
1056 .and_then(|t| t.sub_tables.get(t.next_sub_table))
1057 .is_some_and(|st| st.comp_inlined)
1058 }
1059
1060 fn enter_scope(
1063 &mut self,
1064 name: &str,
1065 scope_type: CompilerScope,
1066 key: usize, lineno: u32,
1068 ) -> CompileResult<()> {
1069 let source_path = self.source_file.name().to_owned();
1073
1074 let ste = match self.symbol_table_stack.get(key) {
1076 Some(v) => v,
1077 None => {
1078 return Err(self.error(CodegenErrorType::SyntaxError(
1079 "unknown symbol table entry".to_owned(),
1080 )));
1081 }
1082 };
1083
1084 let varname_cache: IndexSet<String> = ste.varnames.iter().cloned().collect();
1086
1087 let mut cellvar_cache = IndexSet::default();
1089 let cell_symbols: Vec<_> = ste
1092 .symbols
1093 .iter()
1094 .filter(|(_, s)| {
1095 s.scope == SymbolScope::Cell || s.flags.contains(SymbolFlags::COMP_CELL)
1096 })
1097 .map(|(name, sym)| (name.clone(), sym.flags))
1098 .collect();
1099 let mut param_cells = Vec::new();
1100 let mut nonparam_cells = Vec::new();
1101 for (name, flags) in cell_symbols {
1102 if flags.contains(SymbolFlags::PARAMETER) {
1103 param_cells.push(name);
1104 } else {
1105 nonparam_cells.push(name);
1106 }
1107 }
1108 param_cells.sort_by_key(|n| varname_cache.get_index_of(n.as_str()).unwrap_or(usize::MAX));
1110 nonparam_cells.sort();
1111 for name in param_cells {
1112 cellvar_cache.insert(name);
1113 }
1114 for name in nonparam_cells {
1115 cellvar_cache.insert(name);
1116 }
1117
1118 if ste.needs_class_closure {
1120 debug_assert_eq!(scope_type, CompilerScope::Class);
1122 cellvar_cache.insert("__class__".to_string());
1123 }
1124
1125 if ste.needs_classdict {
1127 debug_assert_eq!(scope_type, CompilerScope::Class);
1129 cellvar_cache.insert("__classdict__".to_string());
1130 }
1131
1132 if ste.has_conditional_annotations
1134 && matches!(scope_type, CompilerScope::Class | CompilerScope::Module)
1135 {
1136 cellvar_cache.insert("__conditional_annotations__".to_string());
1137 }
1138
1139 let mut freevar_cache = IndexSet::default();
1141 let mut free_names: Vec<_> = ste
1142 .symbols
1143 .iter()
1144 .filter(|(_, s)| {
1145 s.scope == SymbolScope::Free || s.flags.contains(SymbolFlags::FREE_CLASS)
1146 })
1147 .map(|(name, _)| name.clone())
1148 .collect();
1149 free_names.sort();
1150 for name in free_names {
1151 freevar_cache.insert(name);
1152 }
1153
1154 let (flags, posonlyarg_count, arg_count, kwonlyarg_count) = match scope_type {
1156 CompilerScope::Module => (bytecode::CodeFlags::empty(), 0, 0, 0),
1157 CompilerScope::Class => (bytecode::CodeFlags::empty(), 0, 0, 0),
1158 CompilerScope::Function | CompilerScope::AsyncFunction | CompilerScope::Lambda => (
1159 bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED,
1160 0, 0, 0, ),
1164 CompilerScope::Comprehension => (
1165 bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED,
1166 0,
1167 1, 0,
1169 ),
1170 CompilerScope::TypeParams => (
1171 bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED,
1172 0,
1173 0,
1174 0,
1175 ),
1176 CompilerScope::Annotation => (
1177 bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED,
1178 1, 1, 0,
1181 ),
1182 };
1183
1184 let flags = if self.code_stack.len() > 1 {
1187 flags | bytecode::CodeFlags::NESTED
1188 } else {
1189 flags
1190 };
1191
1192 let private = if !self.code_stack.is_empty() {
1194 self.code_stack.last().unwrap().private.clone()
1195 } else {
1196 None
1197 };
1198
1199 let code_info = ir::CodeInfo {
1201 flags,
1202 source_path: source_path.clone(),
1203 private,
1204 blocks: vec![ir::Block::default()],
1205 current_block: BlockIdx::new(0),
1206 metadata: ir::CodeUnitMetadata {
1207 name: name.to_owned(),
1208 qualname: None, consts: IndexSet::default(),
1210 names: IndexSet::default(),
1211 varnames: varname_cache,
1212 cellvars: cellvar_cache,
1213 freevars: freevar_cache,
1214 fast_hidden: IndexMap::default(),
1215 argcount: arg_count,
1216 posonlyargcount: posonlyarg_count,
1217 kwonlyargcount: kwonlyarg_count,
1218 firstlineno: OneIndexed::new(lineno as usize).unwrap_or(OneIndexed::MIN),
1219 },
1220 static_attributes: if scope_type == CompilerScope::Class {
1221 Some(IndexSet::default())
1222 } else {
1223 None
1224 },
1225 in_inlined_comp: false,
1226 fblock: Vec::with_capacity(MAXBLOCKS),
1227 symbol_table_index: key,
1228 in_conditional_block: 0,
1229 next_conditional_annotation_index: 0,
1230 };
1231
1232 self.code_stack.push(code_info);
1235
1236 if scope_type != CompilerScope::Module {
1238 self.set_qualname();
1239 }
1240
1241 {
1243 let nfrees = self.code_stack.last().unwrap().metadata.freevars.len();
1244 if nfrees > 0 {
1245 emit!(
1246 self,
1247 Instruction::CopyFreeVars {
1248 n: u32::try_from(nfrees).expect("too many freevars"),
1249 }
1250 );
1251 }
1252 }
1253 {
1254 let ncells = self.code_stack.last().unwrap().metadata.cellvars.len();
1255 for i in 0..ncells {
1256 let i_varnum: oparg::VarNum = u32::try_from(i).expect("too many cellvars").into();
1257 emit!(self, Instruction::MakeCell { i: i_varnum });
1258 }
1259 }
1260
1261 self.emit_resume_for_scope(scope_type, lineno);
1264
1265 Ok(())
1266 }
1267
1268 fn emit_resume_for_scope(&mut self, scope_type: CompilerScope, lineno: u32) {
1271 let is_gen =
1273 scope_type == CompilerScope::AsyncFunction || self.current_symbol_table().is_generator;
1274 if is_gen {
1275 emit!(self, Instruction::ReturnGenerator);
1276 emit!(self, Instruction::PopTop);
1277 }
1278
1279 let lineno_override = if scope_type == CompilerScope::Module {
1282 Some(0)
1283 } else {
1284 None
1285 };
1286
1287 let location = SourceLocation {
1289 line: OneIndexed::new(lineno as usize).unwrap_or(OneIndexed::MIN),
1290 character_offset: OneIndexed::MIN, };
1292 let end_location = location; let except_handler = None;
1294
1295 self.current_block().instructions.push(ir::InstructionInfo {
1296 instr: Instruction::Resume {
1297 context: OpArgMarker::marker(),
1298 }
1299 .into(),
1300 arg: OpArg::new(oparg::ResumeLocation::AtFuncStart.into()),
1301 target: BlockIdx::NULL,
1302 location,
1303 end_location,
1304 except_handler,
1305 lineno_override,
1306 cache_entries: 0,
1307 });
1308 }
1309
1310 fn push_output(
1311 &mut self,
1312 flags: bytecode::CodeFlags,
1313 posonlyarg_count: u32,
1314 arg_count: u32,
1315 kwonlyarg_count: u32,
1316 obj_name: String,
1317 ) -> CompileResult<()> {
1318 let table = self.push_symbol_table()?;
1320 let scope_type = table.typ;
1321
1322 let key = self.symbol_table_stack.len() - 1;
1324
1325 let lineno = self.get_source_line_number().get();
1327
1328 self.enter_scope(&obj_name, scope_type, key, lineno.to_u32())?;
1330
1331 if let Some(info) = self.code_stack.last_mut() {
1335 info.flags = flags | (info.flags & bytecode::CodeFlags::NESTED);
1337 info.metadata.argcount = arg_count;
1338 info.metadata.posonlyargcount = posonlyarg_count;
1339 info.metadata.kwonlyargcount = kwonlyarg_count;
1340 }
1341 Ok(())
1342 }
1343
1344 fn exit_scope(&mut self) -> CodeObject {
1346 let _table = self.pop_symbol_table();
1347
1348 let pop = self.code_stack.pop();
1355 let stack_top = compiler_unwrap_option(self, pop);
1356 unwrap_internal(self, stack_top.finalize_code(&self.opts))
1358 }
1359
1360 fn exit_annotation_scope(&mut self, saved_ctx: CompileContext) -> CodeObject {
1362 self.pop_annotation_symbol_table();
1363 self.ctx = saved_ctx;
1364
1365 let pop = self.code_stack.pop();
1366 let stack_top = compiler_unwrap_option(self, pop);
1367 unwrap_internal(self, stack_top.finalize_code(&self.opts))
1368 }
1369
1370 fn enter_annotation_scope(
1374 &mut self,
1375 _func_name: &str,
1376 ) -> CompileResult<Option<CompileContext>> {
1377 if !self.push_annotation_symbol_table() {
1378 return Ok(None);
1379 }
1380
1381 let saved_ctx = self.ctx;
1383 self.ctx = CompileContext {
1384 loop_data: None,
1385 in_class: saved_ctx.in_class,
1386 func: FunctionContext::Function,
1387 in_async_scope: false,
1388 };
1389
1390 let key = self.symbol_table_stack.len() - 1;
1391 let lineno = self.get_source_line_number().get();
1392 self.enter_scope(
1393 "__annotate__",
1394 CompilerScope::Annotation,
1395 key,
1396 lineno.to_u32(),
1397 )?;
1398
1399 self.current_code_info()
1402 .metadata
1403 .varnames
1404 .insert("format".to_owned());
1405
1406 self.emit_format_validation()?;
1409
1410 Ok(Some(saved_ctx))
1411 }
1412
1413 fn emit_format_validation(&mut self) -> CompileResult<()> {
1416 emit!(
1418 self,
1419 Instruction::LoadFast {
1420 var_num: oparg::VarNum::from_u32(0)
1421 }
1422 );
1423
1424 self.emit_load_const(ConstantData::Integer { value: 2.into() });
1426
1427 emit!(
1429 self,
1430 Instruction::CompareOp {
1431 opname: ComparisonOperator::Greater
1432 }
1433 );
1434
1435 let body_block = self.new_block();
1437 emit!(self, Instruction::PopJumpIfFalse { delta: body_block });
1438
1439 emit!(
1441 self,
1442 Instruction::LoadCommonConstant {
1443 idx: bytecode::CommonConstant::NotImplementedError
1444 }
1445 );
1446 emit!(
1447 self,
1448 Instruction::RaiseVarargs {
1449 argc: bytecode::RaiseKind::Raise
1450 }
1451 );
1452
1453 self.switch_to_block(body_block);
1455
1456 Ok(())
1457 }
1458
1459 fn push_fblock(
1462 &mut self,
1463 fb_type: FBlockType,
1464 fb_block: BlockIdx,
1465 fb_exit: BlockIdx,
1466 ) -> CompileResult<()> {
1467 self.push_fblock_full(fb_type, fb_block, fb_exit, FBlockDatum::None)
1468 }
1469
1470 fn push_fblock_full(
1472 &mut self,
1473 fb_type: FBlockType,
1474 fb_block: BlockIdx,
1475 fb_exit: BlockIdx,
1476 fb_datum: FBlockDatum,
1477 ) -> CompileResult<()> {
1478 let code = self.current_code_info();
1479 if code.fblock.len() >= MAXBLOCKS {
1480 return Err(self.error(CodegenErrorType::SyntaxError(
1481 "too many statically nested blocks".to_owned(),
1482 )));
1483 }
1484 code.fblock.push(FBlockInfo {
1485 fb_type,
1486 fb_block,
1487 fb_exit,
1488 fb_datum,
1489 });
1490 Ok(())
1491 }
1492
1493 fn pop_fblock(&mut self, _expected_type: FBlockType) -> FBlockInfo {
1496 let code = self.current_code_info();
1497 code.fblock.pop().expect("fblock stack underflow")
1500 }
1501
1502 fn unwind_fblock(&mut self, info: &FBlockInfo, preserve_tos: bool) -> CompileResult<()> {
1505 match info.fb_type {
1506 FBlockType::WhileLoop
1507 | FBlockType::ExceptionHandler
1508 | FBlockType::ExceptionGroupHandler
1509 | FBlockType::AsyncComprehensionGenerator
1510 | FBlockType::StopIteration => {
1511 }
1513
1514 FBlockType::ForLoop => {
1515 if preserve_tos {
1517 emit!(self, Instruction::Swap { i: 2 });
1518 }
1519 emit!(self, Instruction::PopIter);
1520 }
1521
1522 FBlockType::TryExcept => {
1523 emit!(self, PseudoInstruction::PopBlock);
1524 }
1525
1526 FBlockType::FinallyTry => {
1527 unreachable!("FinallyTry should be handled by unwind_fblock_stack");
1531 }
1532
1533 FBlockType::FinallyEnd => {
1534 if preserve_tos {
1536 emit!(self, Instruction::Swap { i: 2 });
1537 }
1538 emit!(self, Instruction::PopTop); if preserve_tos {
1540 emit!(self, Instruction::Swap { i: 2 });
1541 }
1542 emit!(self, PseudoInstruction::PopBlock);
1543 emit!(self, Instruction::PopExcept);
1544 }
1545
1546 FBlockType::With | FBlockType::AsyncWith => {
1547 emit!(self, PseudoInstruction::PopBlock);
1549
1550 if preserve_tos {
1551 emit!(self, Instruction::Swap { i: 3 }); emit!(self, Instruction::Swap { i: 2 }); }
1556
1557 self.emit_load_const(ConstantData::None);
1559 self.emit_load_const(ConstantData::None);
1560 self.emit_load_const(ConstantData::None);
1561 emit!(self, Instruction::Call { argc: 3 });
1562
1563 if matches!(info.fb_type, FBlockType::AsyncWith) {
1565 emit!(self, Instruction::GetAwaitable { r#where: 2 });
1566 self.emit_load_const(ConstantData::None);
1567 let _ = self.compile_yield_from_sequence(true)?;
1568 }
1569
1570 emit!(self, Instruction::PopTop);
1572 }
1573
1574 FBlockType::HandlerCleanup => {
1575 if let FBlockDatum::ExceptionName(_) = info.fb_datum {
1577 emit!(self, PseudoInstruction::PopBlock);
1579 }
1580 if preserve_tos {
1581 emit!(self, Instruction::Swap { i: 2 });
1582 }
1583 emit!(self, PseudoInstruction::PopBlock);
1585 emit!(self, Instruction::PopExcept);
1586
1587 if let FBlockDatum::ExceptionName(ref name) = info.fb_datum {
1589 self.emit_load_const(ConstantData::None);
1590 self.store_name(name)?;
1591 self.compile_name(name, NameUsage::Delete)?;
1592 }
1593 }
1594
1595 FBlockType::PopValue => {
1596 if preserve_tos {
1597 emit!(self, Instruction::Swap { i: 2 });
1598 }
1599 emit!(self, Instruction::PopTop);
1600 }
1601 }
1602 Ok(())
1603 }
1604
1605 fn unwind_fblock_stack(&mut self, preserve_tos: bool, stop_at_loop: bool) -> CompileResult<()> {
1609 #[derive(Clone)]
1611 enum UnwindInfo {
1612 Normal(FBlockInfo),
1613 FinallyTry {
1614 body: Vec<ruff_python_ast::Stmt>,
1615 fblock_idx: usize,
1616 },
1617 }
1618 let mut unwind_infos = Vec::new();
1619
1620 {
1621 let code = self.current_code_info();
1622 for i in (0..code.fblock.len()).rev() {
1623 if matches!(code.fblock[i].fb_type, FBlockType::ExceptionGroupHandler) {
1625 return Err(self.error(CodegenErrorType::BreakContinueReturnInExceptStar));
1626 }
1627
1628 if stop_at_loop
1630 && matches!(
1631 code.fblock[i].fb_type,
1632 FBlockType::WhileLoop | FBlockType::ForLoop
1633 )
1634 {
1635 break;
1636 }
1637
1638 if matches!(code.fblock[i].fb_type, FBlockType::FinallyTry) {
1639 if let FBlockDatum::FinallyBody(ref body) = code.fblock[i].fb_datum {
1640 unwind_infos.push(UnwindInfo::FinallyTry {
1641 body: body.clone(),
1642 fblock_idx: i,
1643 });
1644 }
1645 } else {
1646 unwind_infos.push(UnwindInfo::Normal(code.fblock[i].clone()));
1647 }
1648 }
1649 }
1650
1651 for info in unwind_infos {
1653 match info {
1654 UnwindInfo::Normal(fblock_info) => {
1655 self.unwind_fblock(&fblock_info, preserve_tos)?;
1656 }
1657 UnwindInfo::FinallyTry { body, fblock_idx } => {
1658 emit!(self, PseudoInstruction::PopBlock);
1660
1661 let code = self.current_code_info();
1664 let saved_fblock = code.fblock.remove(fblock_idx);
1665
1666 if preserve_tos {
1668 self.push_fblock(
1669 FBlockType::PopValue,
1670 saved_fblock.fb_block,
1671 saved_fblock.fb_block,
1672 )?;
1673 }
1674
1675 self.compile_statements(&body)?;
1676
1677 if preserve_tos {
1678 self.pop_fblock(FBlockType::PopValue);
1679 }
1680
1681 let code = self.current_code_info();
1683 code.fblock.insert(fblock_idx, saved_fblock);
1684 }
1685 }
1686 }
1687
1688 Ok(())
1689 }
1690
1691 fn name(&mut self, name: &str) -> bytecode::NameIdx {
1694 self._name_inner(name, |i| &mut i.metadata.names)
1695 }
1696
1697 fn varname(&mut self, name: &str) -> CompileResult<oparg::VarNum> {
1698 Ok(oparg::VarNum::from_u32(
1700 self._name_inner(name, |i| &mut i.metadata.varnames),
1701 ))
1702 }
1703
1704 fn _name_inner(
1705 &mut self,
1706 name: &str,
1707 cache: impl FnOnce(&mut ir::CodeInfo) -> &mut IndexSet<String>,
1708 ) -> u32 {
1709 let name = self.mangle(name);
1710 let cache = cache(self.current_code_info());
1711 cache
1712 .get_index_of(name.as_ref())
1713 .unwrap_or_else(|| cache.insert_full(name.into_owned()).0)
1714 .to_u32()
1715 }
1716
1717 fn set_qualname(&mut self) -> String {
1720 let qualname = self.make_qualname();
1721 self.current_code_info().metadata.qualname = Some(qualname.clone());
1722 qualname
1723 }
1724 fn make_qualname(&mut self) -> String {
1725 let stack_size = self.code_stack.len();
1726 assert!(stack_size >= 1);
1727
1728 let current_obj_name = self.current_code_info().metadata.name.clone();
1729
1730 if stack_size <= 1 {
1732 return current_obj_name;
1733 }
1734
1735 let mut parent_idx = stack_size - 2;
1737 let mut parent = &self.code_stack[parent_idx];
1738
1739 if parent.metadata.name.starts_with("<generic parameters of ") {
1742 if stack_size == 2 {
1743 return current_obj_name;
1745 }
1746 parent_idx = stack_size - 3;
1748 parent = &self.code_stack[parent_idx];
1749 }
1750
1751 let mut force_global = false;
1753 if stack_size > self.symbol_table_stack.len() {
1754 if let Some(parent_table) = self.symbol_table_stack.last()
1757 && let Some(symbol) = parent_table.lookup(¤t_obj_name)
1758 && symbol.scope == SymbolScope::GlobalExplicit
1759 {
1760 force_global = true;
1761 }
1762 } else if let Some(_current_table) = self.symbol_table_stack.last() {
1763 let mangled_name = self.mangle(¤t_obj_name);
1765
1766 if self.symbol_table_stack.len() >= 2 {
1768 let parent_table = &self.symbol_table_stack[self.symbol_table_stack.len() - 2];
1769 if let Some(symbol) = parent_table.lookup(&mangled_name)
1770 && symbol.scope == SymbolScope::GlobalExplicit
1771 {
1772 force_global = true;
1773 }
1774 }
1775 }
1776
1777 if force_global {
1779 current_obj_name
1781 } else {
1782 let parent_obj_name = &parent.metadata.name;
1784
1785 let is_function_parent = parent.flags.contains(bytecode::CodeFlags::OPTIMIZED)
1787 && !parent_obj_name.starts_with("<") && parent_obj_name != "<module>"; if is_function_parent {
1791 let parent_qualname = parent.metadata.qualname.as_ref().unwrap_or(parent_obj_name);
1794 format!("{parent_qualname}.<locals>.{current_obj_name}")
1795 } else {
1796 let parent_qualname = parent.metadata.qualname.as_ref().unwrap_or(parent_obj_name);
1799 if parent_qualname == "<module>" {
1800 current_obj_name
1802 } else {
1803 format!("{parent_qualname}.{current_obj_name}")
1805 }
1806 }
1807 }
1808 }
1809
1810 fn compile_program(
1811 &mut self,
1812 body: &ast::ModModule,
1813 symbol_table: SymbolTable,
1814 ) -> CompileResult<()> {
1815 let size_before = self.code_stack.len();
1816 self.future_annotations = symbol_table.future_annotations;
1818
1819 let has_module_cond_ann = symbol_table.has_conditional_annotations;
1821 if has_module_cond_ann {
1822 self.current_code_info()
1823 .metadata
1824 .cellvars
1825 .insert("__conditional_annotations__".to_string());
1826 }
1827
1828 self.symbol_table_stack.push(symbol_table);
1829
1830 if has_module_cond_ann {
1832 let ncells = self.code_stack.last().unwrap().metadata.cellvars.len();
1833 for i in 0..ncells {
1834 let i_varnum: oparg::VarNum = u32::try_from(i).expect("too many cellvars").into();
1835 emit!(self, Instruction::MakeCell { i: i_varnum });
1836 }
1837 }
1838
1839 self.emit_resume_for_scope(CompilerScope::Module, 1);
1840
1841 let (doc, statements) = split_doc(&body.body, &self.opts);
1842 if let Some(value) = doc {
1843 self.emit_load_const(ConstantData::Str {
1844 value: value.into(),
1845 });
1846 let doc = self.name("__doc__");
1847 emit!(self, Instruction::StoreName { namei: doc })
1848 }
1849
1850 if Self::find_ann(statements) {
1852 if self.future_annotations {
1853 emit!(self, Instruction::SetupAnnotations);
1855 } else {
1856 self.compile_module_annotate(statements)?;
1858
1859 if self.current_symbol_table().has_conditional_annotations {
1861 emit!(self, Instruction::BuildSet { count: 0 });
1862 self.store_name("__conditional_annotations__")?;
1863 }
1864 }
1865 }
1866
1867 self.compile_statements(statements)?;
1869
1870 assert_eq!(self.code_stack.len(), size_before);
1871
1872 self.emit_return_const(ConstantData::None);
1874 Ok(())
1875 }
1876
1877 fn compile_program_single(
1878 &mut self,
1879 body: &[ast::Stmt],
1880 symbol_table: SymbolTable,
1881 ) -> CompileResult<()> {
1882 self.interactive = true;
1883 self.future_annotations = symbol_table.future_annotations;
1885 self.symbol_table_stack.push(symbol_table);
1886
1887 self.emit_resume_for_scope(CompilerScope::Module, 1);
1888
1889 if Self::find_ann(body) {
1891 if self.future_annotations {
1892 emit!(self, Instruction::SetupAnnotations);
1894 } else {
1895 self.compile_module_annotate(body)?;
1897
1898 if self.current_symbol_table().has_conditional_annotations {
1900 emit!(self, Instruction::BuildSet { count: 0 });
1901 self.store_name("__conditional_annotations__")?;
1902 }
1903 }
1904 }
1905
1906 if let Some((last, body)) = body.split_last() {
1907 for statement in body {
1908 if let ast::Stmt::Expr(ast::StmtExpr { value, .. }) = &statement {
1909 self.compile_expression(value)?;
1910 emit!(
1911 self,
1912 Instruction::CallIntrinsic1 {
1913 func: bytecode::IntrinsicFunction1::Print
1914 }
1915 );
1916
1917 emit!(self, Instruction::PopTop);
1918 } else {
1919 self.compile_statement(statement)?;
1920 }
1921 }
1922
1923 if let ast::Stmt::Expr(ast::StmtExpr { value, .. }) = &last {
1924 self.compile_expression(value)?;
1925 emit!(self, Instruction::Copy { i: 1 });
1926 emit!(
1927 self,
1928 Instruction::CallIntrinsic1 {
1929 func: bytecode::IntrinsicFunction1::Print
1930 }
1931 );
1932
1933 emit!(self, Instruction::PopTop);
1934 } else {
1935 self.compile_statement(last)?;
1936 self.emit_load_const(ConstantData::None);
1937 }
1938 } else {
1939 self.emit_load_const(ConstantData::None);
1940 };
1941
1942 self.emit_return_value();
1943 Ok(())
1944 }
1945
1946 fn compile_block_expr(
1947 &mut self,
1948 body: &[ast::Stmt],
1949 symbol_table: SymbolTable,
1950 ) -> CompileResult<()> {
1951 self.symbol_table_stack.push(symbol_table);
1952 self.emit_resume_for_scope(CompilerScope::Module, 1);
1953
1954 self.compile_statements(body)?;
1955
1956 if let Some(last_statement) = body.last() {
1957 match last_statement {
1958 ast::Stmt::Expr(_) => {
1959 self.current_block().instructions.pop(); }
1961 ast::Stmt::FunctionDef(_) | ast::Stmt::ClassDef(_) => {
1962 let pop_instructions = self.current_block().instructions.pop();
1963 let store_inst = compiler_unwrap_option(self, pop_instructions); emit!(self, Instruction::Copy { i: 1 });
1965 self.current_block().instructions.push(store_inst);
1966 }
1967 _ => self.emit_load_const(ConstantData::None),
1968 }
1969 }
1970 self.emit_return_value();
1971
1972 Ok(())
1973 }
1974
1975 fn compile_eval(
1977 &mut self,
1978 expression: &ast::ModExpression,
1979 symbol_table: SymbolTable,
1980 ) -> CompileResult<()> {
1981 self.symbol_table_stack.push(symbol_table);
1982 self.emit_resume_for_scope(CompilerScope::Module, 1);
1983
1984 self.compile_expression(&expression.body)?;
1985 self.emit_return_value();
1986 Ok(())
1987 }
1988
1989 fn compile_statements(&mut self, statements: &[ast::Stmt]) -> CompileResult<()> {
1990 for statement in statements {
1991 self.compile_statement(statement)?
1992 }
1993 Ok(())
1994 }
1995
1996 fn load_name(&mut self, name: &str) -> CompileResult<()> {
1997 self.compile_name(name, NameUsage::Load)
1998 }
1999
2000 fn store_name(&mut self, name: &str) -> CompileResult<()> {
2001 self.compile_name(name, NameUsage::Store)
2002 }
2003
2004 fn mangle<'a>(&self, name: &'a str) -> Cow<'a, str> {
2005 let private = self
2007 .code_stack
2008 .last()
2009 .and_then(|info| info.private.as_deref());
2010 let mangled_names = self.current_symbol_table().mangled_names.as_ref();
2011 symboltable::maybe_mangle_name(private, mangled_names, name)
2012 }
2013
2014 fn module_name_declared_global_in_nested_scope(table: &SymbolTable, name: &str) -> bool {
2015 table.sub_tables.iter().any(|subtable| {
2016 (!subtable.comp_inlined
2017 && subtable
2018 .lookup(name)
2019 .is_some_and(|symbol| symbol.scope == SymbolScope::GlobalExplicit))
2020 || Self::module_name_declared_global_in_nested_scope(subtable, name)
2021 })
2022 }
2023
2024 fn compile_name(&mut self, name: &str, usage: NameUsage) -> CompileResult<()> {
2026 enum NameOp {
2027 Fast,
2028 Global,
2029 Deref,
2030 Name,
2031 DictOrGlobals, }
2033
2034 let name = self.mangle(name);
2035
2036 if NameUsage::Load == usage && name == "__debug__" {
2038 self.emit_load_const(ConstantData::Boolean {
2039 value: self.opts.optimize == 0,
2040 });
2041 return Ok(());
2042 }
2043
2044 let is_function_like = self.ctx.in_func();
2046
2047 let (symbol_scope, can_see_class_scope) = {
2049 let current_table = self.current_symbol_table();
2050 let is_typeparams = current_table.typ == CompilerScope::TypeParams;
2051 let is_annotation = current_table.typ == CompilerScope::Annotation;
2052 let can_see_class = current_table.can_see_class_scope;
2053
2054 let symbol = current_table.lookup(name.as_ref());
2056
2057 let symbol = if symbol.is_none() && (is_typeparams || is_annotation) {
2059 self.symbol_table_stack
2060 .get(self.symbol_table_stack.len() - 2) .expect("Symbol has no parent! This is a compiler bug.")
2062 .lookup(name.as_ref())
2063 } else {
2064 symbol
2065 };
2066
2067 (symbol.map(|s| s.scope), can_see_class)
2068 };
2069
2070 let symbol_scope = {
2076 let current_table = self.current_symbol_table();
2077 if current_table.typ == CompilerScope::Class
2078 && ((usage == NameUsage::Load
2079 && (name == "__class__"
2080 || name == "__classdict__"
2081 || name == "__conditional_annotations__"))
2082 || (name == "__conditional_annotations__" && usage == NameUsage::Store))
2083 {
2084 Some(SymbolScope::Cell)
2085 } else {
2086 symbol_scope
2087 }
2088 };
2089
2090 let actual_scope = match symbol_scope {
2094 Some(scope) => scope,
2095 None => {
2096 let current_table = self.current_symbol_table();
2097 if matches!(
2098 current_table.typ,
2099 CompilerScope::Annotation | CompilerScope::TypeParams
2100 ) {
2101 SymbolScope::GlobalImplicit
2102 } else {
2103 return Err(self.error(CodegenErrorType::SyntaxError(format!(
2104 "the symbol '{name}' must be present in the symbol table"
2105 ))));
2106 }
2107 }
2108 };
2109
2110 let module_global_from_nested_scope = {
2111 let current_table = self.current_symbol_table();
2112 current_table.typ == CompilerScope::Module
2113 && Self::module_name_declared_global_in_nested_scope(current_table, name.as_ref())
2114 };
2115
2116 let op_type = match actual_scope {
2118 SymbolScope::Free => NameOp::Deref,
2119 SymbolScope::Cell => NameOp::Deref,
2120 SymbolScope::Local => {
2121 if module_global_from_nested_scope {
2122 NameOp::Global
2123 } else if is_function_like {
2124 NameOp::Fast
2125 } else {
2126 NameOp::Name
2127 }
2128 }
2129 SymbolScope::GlobalImplicit => {
2130 if can_see_class_scope {
2133 NameOp::DictOrGlobals
2134 } else if is_function_like {
2135 NameOp::Global
2136 } else {
2137 NameOp::Name
2138 }
2139 }
2140 SymbolScope::GlobalExplicit => NameOp::Global,
2141 SymbolScope::Unknown => {
2142 if module_global_from_nested_scope {
2143 NameOp::Global
2144 } else {
2145 NameOp::Name
2146 }
2147 }
2148 };
2149
2150 match op_type {
2152 NameOp::Deref => {
2153 let i = match actual_scope {
2154 SymbolScope::Free => self.get_free_var_index(&name)?,
2155 SymbolScope::Cell => self.get_cell_var_index(&name)?,
2156 _ => unreachable!("Invalid scope for Deref operation"),
2157 };
2158
2159 if self.current_code_info().in_inlined_comp {
2161 let info = self.code_stack.last_mut().unwrap();
2162 if info
2163 .metadata
2164 .fast_hidden
2165 .get(name.as_ref())
2166 .is_none_or(|&v| v)
2167 {
2168 info.metadata.fast_hidden.insert(name.to_string(), true);
2169 }
2170 }
2171
2172 match usage {
2173 NameUsage::Load => {
2174 if self.ctx.in_class && !self.ctx.in_func() {
2176 emit!(self, Instruction::LoadLocals);
2177 emit!(self, Instruction::LoadFromDictOrDeref { i });
2178 } else if can_see_class_scope {
2180 let classdict_idx = self.get_free_var_index("__classdict__")?;
2181 emit!(self, Instruction::LoadDeref { i: classdict_idx });
2182 emit!(self, Instruction::LoadFromDictOrDeref { i });
2183 } else {
2184 emit!(self, Instruction::LoadDeref { i });
2185 }
2186 }
2187 NameUsage::Store => emit!(self, Instruction::StoreDeref { i }),
2188 NameUsage::Delete => emit!(self, Instruction::DeleteDeref { i }),
2189 };
2190 }
2191 NameOp::Fast => {
2192 let var_num = self.get_local_var_index(&name)?;
2193 if self.current_code_info().in_inlined_comp {
2195 let info = self.code_stack.last_mut().unwrap();
2196 if info
2197 .metadata
2198 .fast_hidden
2199 .get(name.as_ref())
2200 .is_none_or(|&v| v)
2201 {
2202 info.metadata.fast_hidden.insert(name.to_string(), true);
2203 }
2204 }
2205 match usage {
2206 NameUsage::Load => emit!(self, Instruction::LoadFast { var_num }),
2207 NameUsage::Store => emit!(self, Instruction::StoreFast { var_num }),
2208 NameUsage::Delete => emit!(self, Instruction::DeleteFast { var_num }),
2209 };
2210 }
2211 NameOp::Global => {
2212 let namei = self.get_global_name_index(&name);
2213 match usage {
2214 NameUsage::Load => {
2215 self.emit_load_global(namei, false);
2216 return Ok(());
2217 }
2218 NameUsage::Store => emit!(self, Instruction::StoreGlobal { namei }),
2219 NameUsage::Delete => emit!(self, Instruction::DeleteGlobal { namei }),
2220 };
2221 }
2222 NameOp::Name => {
2223 let namei = self.get_global_name_index(&name);
2224 match usage {
2225 NameUsage::Load => emit!(self, Instruction::LoadName { namei }),
2226 NameUsage::Store => emit!(self, Instruction::StoreName { namei }),
2227 NameUsage::Delete => emit!(self, Instruction::DeleteName { namei }),
2228 };
2229 }
2230 NameOp::DictOrGlobals => {
2231 let idx = self.get_global_name_index(&name);
2233 match usage {
2234 NameUsage::Load => {
2235 let classdict_idx = self.get_free_var_index("__classdict__")?;
2237 emit!(self, Instruction::LoadDeref { i: classdict_idx });
2238 emit!(self, Instruction::LoadFromDictOrGlobals { i: idx });
2239 }
2240 NameUsage::Store => {
2242 emit!(self, Instruction::StoreName { namei: idx });
2243 }
2244 NameUsage::Delete => {
2245 emit!(self, Instruction::DeleteName { namei: idx });
2246 }
2247 }
2248 }
2249 }
2250
2251 Ok(())
2252 }
2253
2254 fn compile_statement(&mut self, statement: &ast::Stmt) -> CompileResult<()> {
2255 trace!("Compiling {statement:?}");
2256 let prev_source_range = self.current_source_range;
2257 self.set_source_range(statement.range());
2258
2259 match &statement {
2260 ast::Stmt::ImportFrom(ast::StmtImportFrom { module, names, .. })
2263 if module.as_ref().map(|id| id.as_str()) == Some("__future__") =>
2264 {
2265 self.compile_future_features(names)?
2266 }
2267 ast::Stmt::Expr(ast::StmtExpr { value, .. })
2269 if matches!(&**value, ast::Expr::StringLiteral(..))
2270 && matches!(self.done_with_future_stmts, DoneWithFuture::No) =>
2271 {
2272 self.done_with_future_stmts = DoneWithFuture::DoneWithDoc
2273 }
2274 _ => self.done_with_future_stmts = DoneWithFuture::Yes,
2276 }
2277
2278 match &statement {
2279 ast::Stmt::Import(ast::StmtImport { names, .. }) => {
2280 for name in names {
2282 let name = &name;
2283 self.emit_load_const(ConstantData::Integer {
2284 value: num_traits::Zero::zero(),
2285 });
2286 self.emit_load_const(ConstantData::None);
2287 let namei = self.name(&name.name);
2288 emit!(self, Instruction::ImportName { namei });
2289 if let Some(alias) = &name.asname {
2290 let parts: Vec<&str> = name.name.split('.').skip(1).collect();
2291 for (i, part) in parts.iter().enumerate() {
2292 let namei = self.name(part);
2293 emit!(self, Instruction::ImportFrom { namei });
2294 if i < parts.len() - 1 {
2295 emit!(self, Instruction::Swap { i: 2 });
2296 emit!(self, Instruction::PopTop);
2297 }
2298 }
2299 self.store_name(alias.as_str())?;
2300 if !parts.is_empty() {
2301 emit!(self, Instruction::PopTop);
2302 }
2303 } else {
2304 self.store_name(name.name.split('.').next().unwrap())?
2305 }
2306 }
2307 }
2308 ast::Stmt::ImportFrom(ast::StmtImportFrom {
2309 level,
2310 module,
2311 names,
2312 ..
2313 }) => {
2314 let import_star = names.iter().any(|n| &n.name == "*");
2315
2316 let from_list = if import_star {
2317 if self.ctx.in_func() {
2318 return Err(self.error_ranged(
2319 CodegenErrorType::FunctionImportStar,
2320 statement.range(),
2321 ));
2322 }
2323 vec![ConstantData::Str { value: "*".into() }]
2324 } else {
2325 names
2326 .iter()
2327 .map(|n| ConstantData::Str {
2328 value: n.name.as_str().into(),
2329 })
2330 .collect()
2331 };
2332
2333 self.emit_load_const(ConstantData::Integer {
2335 value: (*level).into(),
2336 });
2337 self.emit_load_const(ConstantData::Tuple {
2338 elements: from_list,
2339 });
2340
2341 let module_name = module.as_ref().map_or("", |s| s.as_str());
2342 let module_idx = self.name(module_name);
2343 emit!(self, Instruction::ImportName { namei: module_idx });
2344
2345 if import_star {
2346 emit!(
2348 self,
2349 Instruction::CallIntrinsic1 {
2350 func: bytecode::IntrinsicFunction1::ImportStar
2351 }
2352 );
2353 emit!(self, Instruction::PopTop);
2354 } else {
2355 for name in names {
2358 let name = &name;
2359 let idx = self.name(name.name.as_str());
2360 emit!(self, Instruction::ImportFrom { namei: idx });
2362
2363 if let Some(alias) = &name.asname {
2365 self.store_name(alias.as_str())?
2366 } else {
2367 self.store_name(name.name.as_str())?
2368 }
2369 }
2370
2371 emit!(self, Instruction::PopTop);
2373 }
2374 }
2375 ast::Stmt::Expr(ast::StmtExpr { value, .. }) => {
2376 let dominated_by_interactive =
2379 self.interactive && !self.ctx.in_func() && !self.ctx.in_class;
2380 if !dominated_by_interactive && Self::is_const_expression(value) {
2381 } else {
2383 self.compile_expression(value)?;
2384
2385 if dominated_by_interactive {
2386 emit!(
2387 self,
2388 Instruction::CallIntrinsic1 {
2389 func: bytecode::IntrinsicFunction1::Print
2390 }
2391 );
2392 }
2393
2394 emit!(self, Instruction::PopTop);
2395 }
2396 }
2397 ast::Stmt::Global(_) | ast::Stmt::Nonlocal(_) => {
2398 }
2400 ast::Stmt::If(ast::StmtIf {
2401 test,
2402 body,
2403 elif_else_clauses,
2404 ..
2405 }) => {
2406 self.enter_conditional_block();
2407 self.compile_if(test, body, elif_else_clauses)?;
2408 self.leave_conditional_block();
2409 }
2410 ast::Stmt::While(ast::StmtWhile {
2411 test, body, orelse, ..
2412 }) => self.compile_while(test, body, orelse)?,
2413 ast::Stmt::With(ast::StmtWith {
2414 items,
2415 body,
2416 is_async,
2417 ..
2418 }) => self.compile_with(items, body, *is_async)?,
2419 ast::Stmt::For(ast::StmtFor {
2420 target,
2421 iter,
2422 body,
2423 orelse,
2424 is_async,
2425 ..
2426 }) => self.compile_for(target, iter, body, orelse, *is_async)?,
2427 ast::Stmt::Match(ast::StmtMatch { subject, cases, .. }) => {
2428 self.compile_match(subject, cases)?
2429 }
2430 ast::Stmt::Raise(ast::StmtRaise {
2431 exc, cause, range, ..
2432 }) => {
2433 let kind = match exc {
2434 Some(value) => {
2435 self.compile_expression(value)?;
2436 match cause {
2437 Some(cause) => {
2438 self.compile_expression(cause)?;
2439 bytecode::RaiseKind::RaiseCause
2440 }
2441 None => bytecode::RaiseKind::Raise,
2442 }
2443 }
2444 None => bytecode::RaiseKind::BareRaise,
2445 };
2446 self.set_source_range(*range);
2447 emit!(self, Instruction::RaiseVarargs { argc: kind });
2448 let dead = self.new_block();
2451 self.switch_to_block(dead);
2452 }
2453 ast::Stmt::Try(ast::StmtTry {
2454 body,
2455 handlers,
2456 orelse,
2457 finalbody,
2458 is_star,
2459 ..
2460 }) => {
2461 self.enter_conditional_block();
2462 if *is_star {
2463 self.compile_try_star_except(body, handlers, orelse, finalbody)?
2464 } else {
2465 self.compile_try_statement(body, handlers, orelse, finalbody)?
2466 }
2467 self.leave_conditional_block();
2468 }
2469 ast::Stmt::FunctionDef(ast::StmtFunctionDef {
2470 name,
2471 parameters,
2472 body,
2473 decorator_list,
2474 returns,
2475 type_params,
2476 is_async,
2477 ..
2478 }) => {
2479 validate_duplicate_params(parameters).map_err(|e| self.error(e))?;
2480
2481 self.compile_function_def(
2482 name.as_str(),
2483 parameters,
2484 body,
2485 decorator_list,
2486 returns.as_deref(),
2487 *is_async,
2488 type_params.as_deref(),
2489 )?
2490 }
2491 ast::Stmt::ClassDef(ast::StmtClassDef {
2492 name,
2493 body,
2494 decorator_list,
2495 type_params,
2496 arguments,
2497 ..
2498 }) => self.compile_class_def(
2499 name.as_str(),
2500 body,
2501 decorator_list,
2502 type_params.as_deref(),
2503 arguments.as_deref(),
2504 )?,
2505 ast::Stmt::Assert(ast::StmtAssert { test, msg, .. }) => {
2506 if self.opts.optimize == 0 {
2508 let after_block = self.new_block();
2509 self.compile_jump_if(test, true, after_block)?;
2510
2511 emit!(
2512 self,
2513 Instruction::LoadCommonConstant {
2514 idx: bytecode::CommonConstant::AssertionError
2515 }
2516 );
2517 if let Some(e) = msg {
2518 emit!(self, Instruction::PushNull);
2519 self.compile_expression(e)?;
2520 emit!(self, Instruction::Call { argc: 1 });
2521 }
2522 emit!(
2523 self,
2524 Instruction::RaiseVarargs {
2525 argc: bytecode::RaiseKind::Raise,
2526 }
2527 );
2528
2529 self.switch_to_block(after_block);
2530 } else {
2531 self.consume_skipped_nested_scopes_in_expr(test)?;
2535 if let Some(expr) = msg {
2536 self.consume_skipped_nested_scopes_in_expr(expr)?;
2537 }
2538 }
2539 }
2540 ast::Stmt::Break(_) => {
2541 emit!(self, Instruction::Nop); self.compile_break_continue(statement.range(), true)?;
2544 let dead = self.new_block();
2545 self.switch_to_block(dead);
2546 }
2547 ast::Stmt::Continue(_) => {
2548 emit!(self, Instruction::Nop); self.compile_break_continue(statement.range(), false)?;
2551 let dead = self.new_block();
2552 self.switch_to_block(dead);
2553 }
2554 ast::Stmt::Return(ast::StmtReturn { value, .. }) => {
2555 if !self.ctx.in_func() {
2556 return Err(
2557 self.error_ranged(CodegenErrorType::InvalidReturn, statement.range())
2558 );
2559 }
2560
2561 match value {
2562 Some(v) => {
2563 if self.ctx.func == FunctionContext::AsyncFunction
2564 && self
2565 .current_code_info()
2566 .flags
2567 .contains(bytecode::CodeFlags::GENERATOR)
2568 {
2569 return Err(self.error_ranged(
2570 CodegenErrorType::AsyncReturnValue,
2571 statement.range(),
2572 ));
2573 }
2574 let folded_constant = self.try_fold_constant_expr(v)?;
2575 let preserve_tos = folded_constant.is_none();
2576 if preserve_tos {
2577 self.compile_expression(v)?;
2578 }
2579 self.unwind_fblock_stack(preserve_tos, false)?;
2580 if let Some(constant) = folded_constant {
2581 self.emit_load_const(constant);
2582 }
2583 self.emit_return_value();
2584 }
2585 None => {
2586 self.unwind_fblock_stack(false, false)?;
2588 self.emit_return_const(ConstantData::None);
2589 }
2590 }
2591 let dead = self.new_block();
2592 self.switch_to_block(dead);
2593 }
2594 ast::Stmt::Assign(ast::StmtAssign { targets, value, .. }) => {
2595 self.compile_expression(value)?;
2596
2597 for (i, target) in targets.iter().enumerate() {
2598 if i + 1 != targets.len() {
2599 emit!(self, Instruction::Copy { i: 1 });
2600 }
2601 self.compile_store(target)?;
2602 }
2603 }
2604 ast::Stmt::AugAssign(ast::StmtAugAssign {
2605 target, op, value, ..
2606 }) => self.compile_augassign(target, op, value)?,
2607 ast::Stmt::AnnAssign(ast::StmtAnnAssign {
2608 target,
2609 annotation,
2610 value,
2611 simple,
2612 ..
2613 }) => {
2614 self.compile_annotated_assign(target, annotation, value.as_deref(), *simple)?;
2615 if value.is_none() && self.ctx.in_func() {
2618 self.set_source_range(prev_source_range);
2619 }
2620 }
2621 ast::Stmt::Delete(ast::StmtDelete { targets, .. }) => {
2622 for target in targets {
2623 self.compile_delete(target)?;
2624 }
2625 }
2626 ast::Stmt::Pass(_) => {
2627 emit!(self, Instruction::Nop); }
2629 ast::Stmt::TypeAlias(ast::StmtTypeAlias {
2630 name,
2631 type_params,
2632 value,
2633 ..
2634 }) => {
2635 let Some(name) = name.as_name_expr() else {
2637 return Err(self.error(CodegenErrorType::SyntaxError(
2639 "type alias expect name".to_owned(),
2640 )));
2641 };
2642 let name_string = name.id.to_string();
2643
2644 self.emit_load_const(ConstantData::Str {
2648 value: name_string.clone().into(),
2649 });
2650
2651 if let Some(type_params) = type_params {
2652 self.push_symbol_table()?;
2654 let key = self.symbol_table_stack.len() - 1;
2655 let lineno = self.get_source_line_number().get().to_u32();
2656 let scope_name = format!("<generic parameters of {name_string}>");
2657 self.enter_scope(&scope_name, CompilerScope::TypeParams, key, lineno)?;
2658
2659 let prev_ctx = self.ctx;
2661 self.ctx = CompileContext {
2662 loop_data: None,
2663 in_class: prev_ctx.in_class,
2664 func: FunctionContext::Function,
2665 in_async_scope: false,
2666 };
2667
2668 self.compile_type_params(type_params)?;
2670 self.push_symbol_table()?;
2674 let inner_key = self.symbol_table_stack.len() - 1;
2675 self.enter_scope("TypeAlias", CompilerScope::TypeParams, inner_key, lineno)?;
2676 self.current_code_info().metadata.argcount = 1;
2678 self.current_code_info().metadata.posonlyargcount = 1;
2679 self.current_code_info()
2680 .metadata
2681 .varnames
2682 .insert("format".to_owned());
2683 self.emit_format_validation()?;
2684 self.compile_expression(value)?;
2685 emit!(self, Instruction::ReturnValue);
2686 let value_code = self.exit_scope();
2687 self.make_closure(value_code, bytecode::MakeFunctionFlags::new())?;
2688 emit!(self, Instruction::Swap { i: 2 });
2692 emit!(self, Instruction::BuildTuple { count: 2 });
2696 emit!(self, Instruction::ReturnValue);
2697
2698 let code = self.exit_scope();
2699 self.ctx = prev_ctx;
2700 self.make_closure(code, bytecode::MakeFunctionFlags::new())?;
2701 emit!(self, Instruction::PushNull);
2702 emit!(self, Instruction::Call { argc: 0 });
2703
2704 emit!(self, Instruction::UnpackSequence { count: 2 });
2707 } else {
2708 self.emit_load_const(ConstantData::None);
2710 self.push_symbol_table()?;
2714 let key = self.symbol_table_stack.len() - 1;
2715 let lineno = self.get_source_line_number().get().to_u32();
2716 self.enter_scope("TypeAlias", CompilerScope::TypeParams, key, lineno)?;
2717 self.current_code_info().metadata.argcount = 1;
2719 self.current_code_info().metadata.posonlyargcount = 1;
2720 self.current_code_info()
2721 .metadata
2722 .varnames
2723 .insert("format".to_owned());
2724 self.emit_format_validation()?;
2725
2726 let prev_ctx = self.ctx;
2727 self.ctx = CompileContext {
2728 loop_data: None,
2729 in_class: prev_ctx.in_class,
2730 func: FunctionContext::Function,
2731 in_async_scope: false,
2732 };
2733
2734 self.compile_expression(value)?;
2735 emit!(self, Instruction::ReturnValue);
2736
2737 let code = self.exit_scope();
2738 self.ctx = prev_ctx;
2739 self.make_closure(code, bytecode::MakeFunctionFlags::new())?;
2740 }
2742
2743 emit!(self, Instruction::BuildTuple { count: 3 });
2745 emit!(
2746 self,
2747 Instruction::CallIntrinsic1 {
2748 func: bytecode::IntrinsicFunction1::TypeAlias
2749 }
2750 );
2751 self.store_name(&name_string)?;
2752 }
2753 ast::Stmt::IpyEscapeCommand(_) => todo!(),
2754 }
2755 Ok(())
2756 }
2757
2758 fn compile_delete(&mut self, expression: &ast::Expr) -> CompileResult<()> {
2759 match &expression {
2760 ast::Expr::Name(ast::ExprName { id, .. }) => {
2761 self.compile_name(id.as_str(), NameUsage::Delete)?
2762 }
2763 ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) => {
2764 self.compile_expression(value)?;
2765 let namei = self.name(attr.as_str());
2766 emit!(self, Instruction::DeleteAttr { namei });
2767 }
2768 ast::Expr::Subscript(ast::ExprSubscript {
2769 value, slice, ctx, ..
2770 }) => {
2771 self.compile_subscript(value, slice, *ctx)?;
2772 }
2773 ast::Expr::Tuple(ast::ExprTuple { elts, .. })
2774 | ast::Expr::List(ast::ExprList { elts, .. }) => {
2775 for element in elts {
2776 self.compile_delete(element)?;
2777 }
2778 }
2779 ast::Expr::BinOp(_) | ast::Expr::UnaryOp(_) => {
2780 return Err(self.error(CodegenErrorType::Delete("expression")));
2781 }
2782 _ => return Err(self.error(CodegenErrorType::Delete(expression.python_name()))),
2783 }
2784 Ok(())
2785 }
2786
2787 fn enter_function(&mut self, name: &str, parameters: &ast::Parameters) -> CompileResult<()> {
2788 let mut kw_without_defaults = vec![];
2790 let mut kw_with_defaults = vec![];
2791 for kwonlyarg in ¶meters.kwonlyargs {
2792 if let Some(default) = &kwonlyarg.default {
2793 kw_with_defaults.push((&kwonlyarg.parameter, default));
2794 } else {
2795 kw_without_defaults.push(&kwonlyarg.parameter);
2796 }
2797 }
2798
2799 self.push_output(
2800 bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED,
2801 parameters.posonlyargs.len().to_u32(),
2802 (parameters.posonlyargs.len() + parameters.args.len()).to_u32(),
2803 parameters.kwonlyargs.len().to_u32(),
2804 name.to_owned(),
2805 )?;
2806
2807 let args_iter = core::iter::empty()
2808 .chain(¶meters.posonlyargs)
2809 .chain(¶meters.args)
2810 .map(|arg| &arg.parameter)
2811 .chain(kw_without_defaults)
2812 .chain(kw_with_defaults.into_iter().map(|(arg, _)| arg));
2813 for name in args_iter {
2814 self.varname(name.name.as_str())?;
2815 }
2816
2817 if let Some(name) = parameters.vararg.as_deref() {
2818 self.current_code_info().flags |= bytecode::CodeFlags::VARARGS;
2819 self.varname(name.name.as_str())?;
2820 }
2821 if let Some(name) = parameters.kwarg.as_deref() {
2822 self.current_code_info().flags |= bytecode::CodeFlags::VARKEYWORDS;
2823 self.varname(name.name.as_str())?;
2824 }
2825
2826 Ok(())
2827 }
2828
2829 fn prepare_decorators(&mut self, decorator_list: &[ast::Decorator]) -> CompileResult<()> {
2832 for decorator in decorator_list {
2833 self.compile_expression(&decorator.expression)?;
2834 }
2835 Ok(())
2836 }
2837
2838 fn apply_decorators(&mut self, decorator_list: &[ast::Decorator]) {
2841 for _ in decorator_list {
2842 emit!(self, Instruction::Call { argc: 0 });
2843 }
2844 }
2845
2846 fn compile_type_param_bound_or_default(
2848 &mut self,
2849 expr: &ast::Expr,
2850 name: &str,
2851 allow_starred: bool,
2852 ) -> CompileResult<()> {
2853 self.push_symbol_table()?;
2855
2856 let key = self.symbol_table_stack.len() - 1;
2858 let lineno = self.get_source_line_number().get().to_u32();
2859
2860 self.enter_scope(name, CompilerScope::TypeParams, key, lineno)?;
2862
2863 self.current_code_info().metadata.argcount = 1;
2865 self.current_code_info().metadata.posonlyargcount = 1;
2866 self.current_code_info()
2867 .metadata
2868 .varnames
2869 .insert("format".to_owned());
2870
2871 self.emit_format_validation()?;
2872
2873 let prev_ctx = self.ctx;
2875 self.ctx = CompileContext {
2876 loop_data: None,
2877 in_class: prev_ctx.in_class,
2878 func: FunctionContext::Function,
2879 in_async_scope: false,
2880 };
2881
2882 if allow_starred && matches!(expr, ast::Expr::Starred(_)) {
2884 if let ast::Expr::Starred(starred) = expr {
2885 self.compile_expression(&starred.value)?;
2886 emit!(self, Instruction::UnpackSequence { count: 1 });
2887 }
2888 } else {
2889 self.compile_expression(expr)?;
2890 }
2891
2892 emit!(self, Instruction::ReturnValue);
2894
2895 let code = self.exit_scope();
2897 self.ctx = prev_ctx;
2898
2899 self.make_closure(code, bytecode::MakeFunctionFlags::new())?;
2901
2902 Ok(())
2903 }
2904
2905 fn compile_type_params(&mut self, type_params: &ast::TypeParams) -> CompileResult<()> {
2908 for type_param in &type_params.type_params {
2910 match type_param {
2911 ast::TypeParam::TypeVar(ast::TypeParamTypeVar {
2912 name,
2913 bound,
2914 default,
2915 ..
2916 }) => {
2917 self.emit_load_const(ConstantData::Str {
2918 value: name.as_str().into(),
2919 });
2920
2921 if let Some(expr) = &bound {
2922 let scope_name = if expr.is_tuple_expr() {
2923 format!("<TypeVar constraint of {name}>")
2924 } else {
2925 format!("<TypeVar bound of {name}>")
2926 };
2927 self.compile_type_param_bound_or_default(expr, &scope_name, false)?;
2928
2929 let intrinsic = if expr.is_tuple_expr() {
2930 bytecode::IntrinsicFunction2::TypeVarWithConstraint
2931 } else {
2932 bytecode::IntrinsicFunction2::TypeVarWithBound
2933 };
2934 emit!(self, Instruction::CallIntrinsic2 { func: intrinsic });
2935 } else {
2936 emit!(
2937 self,
2938 Instruction::CallIntrinsic1 {
2939 func: bytecode::IntrinsicFunction1::TypeVar
2940 }
2941 );
2942 }
2943
2944 if let Some(default_expr) = default {
2945 let scope_name = format!("<TypeVar default of {name}>");
2946 self.compile_type_param_bound_or_default(default_expr, &scope_name, false)?;
2947 emit!(
2948 self,
2949 Instruction::CallIntrinsic2 {
2950 func: bytecode::IntrinsicFunction2::SetTypeparamDefault
2951 }
2952 );
2953 }
2954
2955 emit!(self, Instruction::Copy { i: 1 });
2956 self.store_name(name.as_ref())?;
2957 }
2958 ast::TypeParam::ParamSpec(ast::TypeParamParamSpec { name, default, .. }) => {
2959 self.emit_load_const(ConstantData::Str {
2960 value: name.as_str().into(),
2961 });
2962 emit!(
2963 self,
2964 Instruction::CallIntrinsic1 {
2965 func: bytecode::IntrinsicFunction1::ParamSpec
2966 }
2967 );
2968
2969 if let Some(default_expr) = default {
2970 let scope_name = format!("<ParamSpec default of {name}>");
2971 self.compile_type_param_bound_or_default(default_expr, &scope_name, false)?;
2972 emit!(
2973 self,
2974 Instruction::CallIntrinsic2 {
2975 func: bytecode::IntrinsicFunction2::SetTypeparamDefault
2976 }
2977 );
2978 }
2979
2980 emit!(self, Instruction::Copy { i: 1 });
2981 self.store_name(name.as_ref())?;
2982 }
2983 ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple {
2984 name, default, ..
2985 }) => {
2986 self.emit_load_const(ConstantData::Str {
2987 value: name.as_str().into(),
2988 });
2989 emit!(
2990 self,
2991 Instruction::CallIntrinsic1 {
2992 func: bytecode::IntrinsicFunction1::TypeVarTuple
2993 }
2994 );
2995
2996 if let Some(default_expr) = default {
2997 let scope_name = format!("<TypeVarTuple default of {name}>");
2999 self.compile_type_param_bound_or_default(default_expr, &scope_name, true)?;
3000 emit!(
3001 self,
3002 Instruction::CallIntrinsic2 {
3003 func: bytecode::IntrinsicFunction2::SetTypeparamDefault
3004 }
3005 );
3006 }
3007
3008 emit!(self, Instruction::Copy { i: 1 });
3009 self.store_name(name.as_ref())?;
3010 }
3011 };
3012 }
3013 emit!(
3014 self,
3015 Instruction::BuildTuple {
3016 count: u32::try_from(type_params.len()).unwrap(),
3017 }
3018 );
3019 Ok(())
3020 }
3021
3022 fn compile_try_statement(
3023 &mut self,
3024 body: &[ast::Stmt],
3025 handlers: &[ast::ExceptHandler],
3026 orelse: &[ast::Stmt],
3027 finalbody: &[ast::Stmt],
3028 ) -> CompileResult<()> {
3029 if finalbody.is_empty() {
3030 return self.compile_try_except_no_finally(body, handlers, orelse);
3031 }
3032
3033 let handler_block = self.new_block();
3034 let finally_block = self.new_block();
3035
3036 let finally_except_block = if !finalbody.is_empty() {
3040 Some(self.new_block())
3041 } else {
3042 None
3043 };
3044 let finally_cleanup_block = if finally_except_block.is_some() {
3045 Some(self.new_block())
3046 } else {
3047 None
3048 };
3049 let end_block = self.new_block();
3052
3053 emit!(self, Instruction::Nop);
3055
3056 if !finalbody.is_empty() {
3060 let setup_target = finally_except_block.unwrap_or(finally_block);
3063 emit!(
3064 self,
3065 PseudoInstruction::SetupFinally {
3066 delta: setup_target
3067 }
3068 );
3069 self.push_fblock_full(
3071 FBlockType::FinallyTry,
3072 finally_block,
3073 finally_block,
3074 FBlockDatum::FinallyBody(finalbody.to_vec()), )?;
3076 }
3077
3078 let else_block = self.new_block();
3079
3080 if handlers.is_empty() {
3083 self.compile_statements(body)?;
3085
3086 if !finalbody.is_empty() {
3089 emit!(self, PseudoInstruction::PopBlock);
3090 self.pop_fblock(FBlockType::FinallyTry);
3091 }
3092
3093 self.compile_statements(orelse)?;
3095
3096 let sub_table_cursor = if !finalbody.is_empty() && finally_except_block.is_some() {
3099 self.symbol_table_stack.last().map(|t| t.next_sub_table)
3100 } else {
3101 None
3102 };
3103
3104 if !finalbody.is_empty() {
3106 self.compile_statements(finalbody)?;
3107 }
3108
3109 emit!(self, PseudoInstruction::Jump { delta: end_block });
3111
3112 if let Some(finally_except) = finally_except_block {
3113 if let Some(cursor) = sub_table_cursor
3115 && let Some(current_table) = self.symbol_table_stack.last_mut()
3116 {
3117 current_table.next_sub_table = cursor;
3118 }
3119
3120 self.switch_to_block(finally_except);
3121 if let Some(cleanup) = finally_cleanup_block {
3123 emit!(self, PseudoInstruction::SetupCleanup { delta: cleanup });
3124 }
3125 emit!(self, Instruction::PushExcInfo);
3126 if let Some(cleanup) = finally_cleanup_block {
3127 self.push_fblock(FBlockType::FinallyEnd, cleanup, cleanup)?;
3128 }
3129 self.compile_statements(finalbody)?;
3130
3131 if finally_cleanup_block.is_some() {
3135 emit!(self, PseudoInstruction::PopBlock);
3136 self.pop_fblock(FBlockType::FinallyEnd);
3137 }
3138
3139 emit!(self, Instruction::Copy { i: 2 });
3144 emit!(self, Instruction::PopExcept);
3145
3146 emit!(self, Instruction::Reraise { depth: 0 });
3148 }
3149
3150 if let Some(cleanup) = finally_cleanup_block {
3151 self.switch_to_block(cleanup);
3152 emit!(self, Instruction::Copy { i: 3 });
3153 emit!(self, Instruction::PopExcept);
3154 emit!(self, Instruction::Reraise { depth: 1 });
3155 }
3156
3157 self.switch_to_block(end_block);
3158 return Ok(());
3159 }
3160
3161 emit!(
3163 self,
3164 PseudoInstruction::SetupFinally {
3165 delta: handler_block
3166 }
3167 );
3168 self.push_fblock(FBlockType::TryExcept, handler_block, handler_block)?;
3169 self.compile_statements(body)?;
3170 emit!(self, PseudoInstruction::PopBlock);
3171 self.pop_fblock(FBlockType::TryExcept);
3172 emit!(self, PseudoInstruction::Jump { delta: else_block });
3173
3174 self.switch_to_block(handler_block);
3176
3177 let cleanup_block = self.new_block();
3183 emit!(
3184 self,
3185 PseudoInstruction::SetupCleanup {
3186 delta: cleanup_block
3187 }
3188 );
3189 self.push_fblock(FBlockType::ExceptionHandler, cleanup_block, cleanup_block)?;
3190
3191 emit!(self, Instruction::PushExcInfo);
3194 for handler in handlers {
3195 let ast::ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
3196 type_,
3197 name,
3198 body,
3199 range: handler_range,
3200 ..
3201 }) = &handler;
3202 self.set_source_range(*handler_range);
3203 let next_handler = self.new_block();
3204
3205 if let Some(exc_type) = type_ {
3208 self.compile_expression(exc_type)?;
3211 emit!(self, Instruction::CheckExcMatch);
3213 emit!(
3215 self,
3216 Instruction::PopJumpIfFalse {
3217 delta: next_handler
3218 }
3219 );
3220 if let Some(alias) = name {
3224 self.store_name(alias.as_str())?
3225 } else {
3226 emit!(self, Instruction::PopTop);
3228 }
3229 } else {
3230 emit!(self, Instruction::PopTop);
3233 }
3234
3235 let handler_cleanup_block = if name.is_some() {
3237 let cleanup_end = self.new_block();
3239 emit!(self, PseudoInstruction::SetupCleanup { delta: cleanup_end });
3240 self.push_fblock_full(
3241 FBlockType::HandlerCleanup,
3242 cleanup_end,
3243 cleanup_end,
3244 FBlockDatum::ExceptionName(name.as_ref().unwrap().as_str().to_owned()),
3245 )?;
3246 Some(cleanup_end)
3247 } else {
3248 self.push_fblock(FBlockType::HandlerCleanup, finally_block, finally_block)?;
3250 None
3251 };
3252
3253 self.compile_statements(body)?;
3255
3256 self.pop_fblock(FBlockType::HandlerCleanup);
3257 if handler_cleanup_block.is_some() {
3259 emit!(self, PseudoInstruction::PopBlock);
3260 }
3261
3262 if let Some(cleanup_end) = handler_cleanup_block {
3267 let handler_normal_exit = self.new_block();
3268 emit!(
3269 self,
3270 PseudoInstruction::JumpNoInterrupt {
3271 delta: handler_normal_exit,
3272 }
3273 );
3274
3275 self.switch_to_block(cleanup_end);
3276 if let Some(alias) = name {
3277 self.emit_load_const(ConstantData::None);
3279 self.store_name(alias.as_str())?;
3280 self.compile_name(alias.as_str(), NameUsage::Delete)?;
3281 }
3282 emit!(self, Instruction::Reraise { depth: 1 });
3287
3288 self.switch_to_block(handler_normal_exit);
3290 }
3291
3292 emit!(self, PseudoInstruction::PopBlock);
3294 self.pop_fblock(FBlockType::ExceptionHandler);
3296 emit!(self, Instruction::PopExcept);
3297
3298 if let Some(alias) = name {
3300 self.emit_load_const(ConstantData::None);
3302 self.store_name(alias.as_str())?;
3303 self.compile_name(alias.as_str(), NameUsage::Delete)?;
3304 }
3305
3306 if !finalbody.is_empty() {
3310 emit!(self, PseudoInstruction::PopBlock);
3311 }
3312
3313 emit!(
3315 self,
3316 PseudoInstruction::JumpNoInterrupt {
3317 delta: finally_block,
3318 }
3319 );
3320
3321 self.push_fblock(FBlockType::ExceptionHandler, cleanup_block, cleanup_block)?;
3324
3325 self.switch_to_block(next_handler);
3327 }
3328
3329 emit!(self, Instruction::Reraise { depth: 0 });
3335
3336 self.pop_fblock(FBlockType::ExceptionHandler);
3339
3340 self.switch_to_block(cleanup_block);
3346 emit!(self, Instruction::Copy { i: 3 });
3347 emit!(self, Instruction::PopExcept);
3348 emit!(self, Instruction::Reraise { depth: 1 });
3349
3350 self.switch_to_block(else_block);
3353 self.compile_statements(orelse)?;
3354
3355 if !finalbody.is_empty() {
3357 emit!(self, PseudoInstruction::PopBlock);
3358 self.pop_fblock(FBlockType::FinallyTry);
3359 }
3360
3361 let sub_table_cursor = if !finalbody.is_empty() && finally_except_block.is_some() {
3363 self.symbol_table_stack.last().map(|t| t.next_sub_table)
3364 } else {
3365 None
3366 };
3367
3368 self.switch_to_block(finally_block);
3370 if !finalbody.is_empty() {
3371 self.compile_statements(finalbody)?;
3372 emit!(self, PseudoInstruction::Jump { delta: end_block });
3375 }
3376
3377 if let Some(finally_except) = finally_except_block {
3381 if let Some(cursor) = sub_table_cursor
3383 && let Some(current_table) = self.symbol_table_stack.last_mut()
3384 {
3385 current_table.next_sub_table = cursor;
3386 }
3387
3388 self.switch_to_block(finally_except);
3389
3390 if let Some(cleanup) = finally_cleanup_block {
3393 emit!(self, PseudoInstruction::SetupCleanup { delta: cleanup });
3394 }
3395 emit!(self, Instruction::PushExcInfo);
3396 if let Some(cleanup) = finally_cleanup_block {
3397 self.push_fblock(FBlockType::FinallyEnd, cleanup, cleanup)?;
3398 }
3399
3400 self.compile_statements(finalbody)?;
3402
3403 if finally_cleanup_block.is_some() {
3407 emit!(self, PseudoInstruction::PopBlock);
3408 self.pop_fblock(FBlockType::FinallyEnd);
3409 }
3410
3411 emit!(self, Instruction::Copy { i: 2 });
3416 emit!(self, Instruction::PopExcept);
3417
3418 emit!(self, Instruction::Reraise { depth: 0 });
3421 }
3422
3423 if let Some(cleanup) = finally_cleanup_block {
3427 self.switch_to_block(cleanup);
3428 emit!(self, Instruction::Copy { i: 3 });
3430 emit!(self, Instruction::PopExcept);
3432 emit!(self, Instruction::Reraise { depth: 1 });
3434 }
3435
3436 self.switch_to_block(end_block);
3439
3440 Ok(())
3441 }
3442
3443 fn compile_try_except_no_finally(
3444 &mut self,
3445 body: &[ast::Stmt],
3446 handlers: &[ast::ExceptHandler],
3447 orelse: &[ast::Stmt],
3448 ) -> CompileResult<()> {
3449 let handler_block = self.new_block();
3450 let cleanup_block = self.new_block();
3451 let orelse_block = self.new_block();
3452 let end_block = self.new_block();
3453
3454 emit!(self, Instruction::Nop);
3455 emit!(
3456 self,
3457 PseudoInstruction::SetupFinally {
3458 delta: handler_block
3459 }
3460 );
3461
3462 self.push_fblock(FBlockType::TryExcept, handler_block, handler_block)?;
3463 self.compile_statements(body)?;
3464 self.pop_fblock(FBlockType::TryExcept);
3465 emit!(self, PseudoInstruction::PopBlock);
3466 self.set_no_location();
3467 emit!(
3468 self,
3469 PseudoInstruction::JumpNoInterrupt {
3470 delta: orelse_block
3471 }
3472 );
3473 self.set_no_location();
3474
3475 self.switch_to_block(handler_block);
3476 emit!(
3477 self,
3478 PseudoInstruction::SetupCleanup {
3479 delta: cleanup_block
3480 }
3481 );
3482 self.set_no_location();
3483 emit!(self, Instruction::PushExcInfo);
3484 self.set_no_location();
3485 self.push_fblock(FBlockType::ExceptionHandler, cleanup_block, cleanup_block)?;
3486
3487 for handler in handlers {
3488 let ast::ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
3489 type_,
3490 name,
3491 body,
3492 range: handler_range,
3493 ..
3494 }) = handler;
3495 self.set_source_range(*handler_range);
3496 let next_handler = self.new_block();
3497
3498 if let Some(exc_type) = type_ {
3499 self.compile_expression(exc_type)?;
3500 emit!(self, Instruction::CheckExcMatch);
3501 emit!(
3502 self,
3503 Instruction::PopJumpIfFalse {
3504 delta: next_handler
3505 }
3506 );
3507 }
3508
3509 if let Some(alias) = name {
3510 self.store_name(alias.as_str())?;
3511
3512 let cleanup_end = self.new_block();
3513 let handler_normal_exit = self.new_block();
3514 emit!(self, PseudoInstruction::SetupCleanup { delta: cleanup_end });
3515 self.push_fblock_full(
3516 FBlockType::HandlerCleanup,
3517 cleanup_end,
3518 cleanup_end,
3519 FBlockDatum::ExceptionName(alias.as_str().to_owned()),
3520 )?;
3521
3522 self.compile_statements(body)?;
3523
3524 self.pop_fblock(FBlockType::HandlerCleanup);
3525 emit!(self, PseudoInstruction::PopBlock);
3526 self.set_no_location();
3527 emit!(
3528 self,
3529 PseudoInstruction::JumpNoInterrupt {
3530 delta: handler_normal_exit
3531 }
3532 );
3533 self.set_no_location();
3534
3535 self.switch_to_block(cleanup_end);
3536 self.emit_load_const(ConstantData::None);
3537 self.set_no_location();
3538 self.store_name(alias.as_str())?;
3539 self.set_no_location();
3540 self.compile_name(alias.as_str(), NameUsage::Delete)?;
3541 self.set_no_location();
3542 emit!(self, Instruction::Reraise { depth: 1 });
3543 self.set_no_location();
3544
3545 self.switch_to_block(handler_normal_exit);
3546 emit!(self, PseudoInstruction::PopBlock);
3547 self.set_no_location();
3548 self.pop_fblock(FBlockType::ExceptionHandler);
3549 emit!(self, Instruction::PopExcept);
3550 self.set_no_location();
3551
3552 self.emit_load_const(ConstantData::None);
3553 self.set_no_location();
3554 self.store_name(alias.as_str())?;
3555 self.set_no_location();
3556 self.compile_name(alias.as_str(), NameUsage::Delete)?;
3557 self.set_no_location();
3558
3559 emit!(
3560 self,
3561 PseudoInstruction::JumpNoInterrupt { delta: end_block }
3562 );
3563 self.set_no_location();
3564 } else {
3565 emit!(self, Instruction::PopTop);
3566 self.push_fblock(FBlockType::HandlerCleanup, end_block, end_block)?;
3567
3568 self.compile_statements(body)?;
3569
3570 self.pop_fblock(FBlockType::HandlerCleanup);
3571 emit!(self, PseudoInstruction::PopBlock);
3572 self.set_no_location();
3573 self.pop_fblock(FBlockType::ExceptionHandler);
3574 emit!(self, Instruction::PopExcept);
3575 self.set_no_location();
3576 emit!(
3577 self,
3578 PseudoInstruction::JumpNoInterrupt { delta: end_block }
3579 );
3580 self.set_no_location();
3581 }
3582
3583 self.push_fblock(FBlockType::ExceptionHandler, cleanup_block, cleanup_block)?;
3584 self.switch_to_block(next_handler);
3585 }
3586
3587 emit!(self, Instruction::Reraise { depth: 0 });
3588 self.set_no_location();
3589 self.pop_fblock(FBlockType::ExceptionHandler);
3590
3591 self.switch_to_block(cleanup_block);
3592 emit!(self, Instruction::Copy { i: 3 });
3593 self.set_no_location();
3594 emit!(self, Instruction::PopExcept);
3595 self.set_no_location();
3596 emit!(self, Instruction::Reraise { depth: 1 });
3597 self.set_no_location();
3598
3599 self.switch_to_block(orelse_block);
3600 self.set_no_location();
3601 self.compile_statements(orelse)?;
3602 emit!(
3603 self,
3604 PseudoInstruction::JumpNoInterrupt { delta: end_block }
3605 );
3606 self.set_no_location();
3607
3608 self.switch_to_block(end_block);
3609 Ok(())
3610 }
3611
3612 fn compile_try_star_except(
3613 &mut self,
3614 body: &[ast::Stmt],
3615 handlers: &[ast::ExceptHandler],
3616 orelse: &[ast::Stmt],
3617 finalbody: &[ast::Stmt],
3618 ) -> CompileResult<()> {
3619 let handler_block = self.new_block();
3622 let finally_block = self.new_block();
3623 let else_block = self.new_block();
3624 let end_block = self.new_block();
3625 let reraise_star_block = self.new_block();
3626 let reraise_block = self.new_block();
3627 let finally_cleanup_block = if !finalbody.is_empty() {
3628 Some(self.new_block())
3629 } else {
3630 None
3631 };
3632 let exit_block = self.new_block();
3633
3634 emit!(self, Instruction::Nop);
3636
3637 if !finalbody.is_empty() {
3639 emit!(
3640 self,
3641 PseudoInstruction::SetupFinally {
3642 delta: finally_block
3643 }
3644 );
3645 self.push_fblock_full(
3646 FBlockType::FinallyTry,
3647 finally_block,
3648 finally_block,
3649 FBlockDatum::FinallyBody(finalbody.to_vec()),
3650 )?;
3651 }
3652
3653 emit!(
3655 self,
3656 PseudoInstruction::SetupFinally {
3657 delta: handler_block
3658 }
3659 );
3660 self.push_fblock(FBlockType::TryExcept, handler_block, handler_block)?;
3661 self.compile_statements(body)?;
3662 emit!(self, PseudoInstruction::PopBlock);
3663 self.pop_fblock(FBlockType::TryExcept);
3664 emit!(self, PseudoInstruction::Jump { delta: else_block });
3665
3666 self.switch_to_block(handler_block);
3668 emit!(self, Instruction::PushExcInfo);
3672 let eg_dummy1 = self.new_block();
3676 let eg_dummy2 = self.new_block();
3677 self.push_fblock(FBlockType::ExceptionGroupHandler, eg_dummy1, eg_dummy2)?;
3678
3679 emit!(self, Instruction::BuildList { count: 0 });
3682 emit!(self, Instruction::Copy { i: 2 });
3684 let n = handlers.len();
3687 if n == 0 {
3688 emit!(self, Instruction::ListAppend { i: 1 });
3691 emit!(
3693 self,
3694 PseudoInstruction::Jump {
3695 delta: reraise_star_block
3696 }
3697 );
3698 }
3699 for (i, handler) in handlers.iter().enumerate() {
3700 let ast::ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
3701 type_,
3702 name,
3703 body,
3704 ..
3705 }) = handler;
3706
3707 let no_match_block = self.new_block();
3708 let next_block = self.new_block();
3709
3710 if let Some(exc_type) = type_ {
3712 if let ast::Expr::Tuple(ast::ExprTuple { elts, range, .. }) = exc_type.as_ref()
3714 && let Some(first) = elts.first()
3715 && range.start().to_u32() == first.range().start().to_u32()
3716 {
3717 return Err(self.error(CodegenErrorType::SyntaxError(
3718 "multiple exception types must be parenthesized".to_owned(),
3719 )));
3720 }
3721 self.compile_expression(exc_type)?;
3722 } else {
3723 return Err(self.error(CodegenErrorType::SyntaxError(
3724 "except* must specify an exception type".to_owned(),
3725 )));
3726 }
3727 emit!(self, Instruction::CheckEgMatch);
3731 emit!(self, Instruction::Copy { i: 1 });
3736 emit!(
3737 self,
3738 Instruction::PopJumpIfNone {
3739 delta: no_match_block
3740 }
3741 );
3742
3743 let handler_except_block = self.new_block();
3747
3748 if let Some(alias) = name {
3750 self.store_name(alias.as_str())?;
3751 } else {
3752 emit!(self, Instruction::PopTop); }
3754 emit!(
3758 self,
3759 PseudoInstruction::SetupCleanup {
3760 delta: handler_except_block
3761 }
3762 );
3763 self.push_fblock_full(
3764 FBlockType::HandlerCleanup,
3765 next_block,
3766 end_block,
3767 if let Some(alias) = name {
3768 FBlockDatum::ExceptionName(alias.as_str().to_owned())
3769 } else {
3770 FBlockDatum::None
3771 },
3772 )?;
3773
3774 self.compile_statements(body)?;
3776
3777 emit!(self, PseudoInstruction::PopBlock);
3779 self.pop_fblock(FBlockType::HandlerCleanup);
3780
3781 if let Some(alias) = name {
3783 self.emit_load_const(ConstantData::None);
3784 self.store_name(alias.as_str())?;
3785 self.compile_name(alias.as_str(), NameUsage::Delete)?;
3786 }
3787
3788 emit!(self, PseudoInstruction::Jump { delta: next_block });
3790
3791 self.switch_to_block(handler_except_block);
3793 if let Some(alias) = name {
3798 self.emit_load_const(ConstantData::None);
3799 self.store_name(alias.as_str())?;
3800 self.compile_name(alias.as_str(), NameUsage::Delete)?;
3801 }
3802
3803 emit!(self, Instruction::ListAppend { i: 3 });
3809 emit!(self, Instruction::PopTop);
3813 emit!(self, PseudoInstruction::Jump { delta: next_block });
3818
3819 self.switch_to_block(no_match_block);
3821 emit!(self, Instruction::PopTop); self.switch_to_block(next_block);
3828 if i == n - 1 {
3832 emit!(self, Instruction::ListAppend { i: 1 });
3838 emit!(
3840 self,
3841 PseudoInstruction::Jump {
3842 delta: reraise_star_block
3843 }
3844 );
3845 }
3846 }
3847
3848 self.pop_fblock(FBlockType::ExceptionGroupHandler);
3850
3851 self.switch_to_block(reraise_star_block);
3853 emit!(
3858 self,
3859 Instruction::CallIntrinsic2 {
3860 func: bytecode::IntrinsicFunction2::PrepReraiseStar
3861 }
3862 );
3863 emit!(self, Instruction::Copy { i: 1 });
3867 emit!(
3871 self,
3872 Instruction::PopJumpIfNotNone {
3873 delta: reraise_block
3874 }
3875 );
3876 emit!(self, Instruction::PopTop);
3881 emit!(self, Instruction::PopExcept);
3886 if !finalbody.is_empty() {
3889 emit!(self, PseudoInstruction::PopBlock);
3890 self.pop_fblock(FBlockType::FinallyTry);
3891 }
3892
3893 emit!(self, PseudoInstruction::Jump { delta: end_block });
3894
3895 self.switch_to_block(reraise_block);
3897 emit!(self, Instruction::Swap { i: 2 });
3902 emit!(self, Instruction::PopExcept);
3906 emit!(self, Instruction::Reraise { depth: 0 });
3910
3911 if !finalbody.is_empty() {
3917 emit!(
3918 self,
3919 PseudoInstruction::SetupFinally {
3920 delta: finally_block
3921 }
3922 );
3923 self.push_fblock_full(
3924 FBlockType::FinallyTry,
3925 finally_block,
3926 finally_block,
3927 FBlockDatum::FinallyBody(finalbody.to_vec()),
3928 )?;
3929 }
3930 self.switch_to_block(else_block);
3931 self.compile_statements(orelse)?;
3932
3933 if !finalbody.is_empty() {
3934 emit!(self, PseudoInstruction::PopBlock);
3936 self.pop_fblock(FBlockType::FinallyTry);
3937 }
3938
3939 emit!(self, PseudoInstruction::Jump { delta: end_block });
3940
3941 self.switch_to_block(end_block);
3942 if !finalbody.is_empty() {
3943 let sub_table_cursor = self.symbol_table_stack.last().map(|t| t.next_sub_table);
3945
3946 self.compile_statements(finalbody)?;
3948 emit!(self, PseudoInstruction::Jump { delta: exit_block });
3949
3950 if let Some(cursor) = sub_table_cursor
3952 && let Some(current_table) = self.symbol_table_stack.last_mut()
3953 {
3954 current_table.next_sub_table = cursor;
3955 }
3956
3957 self.switch_to_block(finally_block);
3959 emit!(self, Instruction::PushExcInfo);
3960
3961 if let Some(cleanup) = finally_cleanup_block {
3962 emit!(self, PseudoInstruction::SetupCleanup { delta: cleanup });
3963 self.push_fblock(FBlockType::FinallyEnd, cleanup, cleanup)?;
3964 }
3965
3966 self.compile_statements(finalbody)?;
3967
3968 if finally_cleanup_block.is_some() {
3969 emit!(self, PseudoInstruction::PopBlock);
3970 self.pop_fblock(FBlockType::FinallyEnd);
3971 }
3972
3973 emit!(self, Instruction::Copy { i: 2 });
3974 emit!(self, Instruction::PopExcept);
3975 emit!(self, Instruction::Reraise { depth: 0 });
3976
3977 if let Some(cleanup) = finally_cleanup_block {
3978 self.switch_to_block(cleanup);
3979 emit!(self, Instruction::Copy { i: 3 });
3980 emit!(self, Instruction::PopExcept);
3981 emit!(self, Instruction::Reraise { depth: 1 });
3982 }
3983 }
3984
3985 self.switch_to_block(exit_block);
3986
3987 Ok(())
3988 }
3989
3990 fn compile_default_arguments(
3993 &mut self,
3994 parameters: &ast::Parameters,
3995 ) -> CompileResult<bytecode::MakeFunctionFlags> {
3996 let mut funcflags = bytecode::MakeFunctionFlags::new();
3997
3998 let defaults: Vec<_> = core::iter::empty()
4000 .chain(¶meters.posonlyargs)
4001 .chain(¶meters.args)
4002 .filter_map(|x| x.default.as_deref())
4003 .collect();
4004
4005 if !defaults.is_empty() {
4006 for default in &defaults {
4008 self.compile_expression(default)?;
4009 }
4010 emit!(
4011 self,
4012 Instruction::BuildTuple {
4013 count: defaults.len().to_u32()
4014 }
4015 );
4016 funcflags.insert(bytecode::MakeFunctionFlag::Defaults);
4017 }
4018
4019 let mut kw_with_defaults = vec![];
4021 for kwonlyarg in ¶meters.kwonlyargs {
4022 if let Some(default) = &kwonlyarg.default {
4023 kw_with_defaults.push((&kwonlyarg.parameter, default));
4024 }
4025 }
4026
4027 if !kw_with_defaults.is_empty() {
4028 for (arg, default) in &kw_with_defaults {
4030 self.emit_load_const(ConstantData::Str {
4031 value: self.mangle(arg.name.as_str()).into_owned().into(),
4032 });
4033 self.compile_expression(default)?;
4034 }
4035 emit!(
4036 self,
4037 Instruction::BuildMap {
4038 count: kw_with_defaults.len().to_u32(),
4039 }
4040 );
4041 funcflags.insert(bytecode::MakeFunctionFlag::KwOnlyDefaults);
4042 }
4043
4044 Ok(funcflags)
4045 }
4046
4047 fn compile_function_body(
4050 &mut self,
4051 name: &str,
4052 parameters: &ast::Parameters,
4053 body: &[ast::Stmt],
4054 is_async: bool,
4055 funcflags: bytecode::MakeFunctionFlags,
4056 ) -> CompileResult<()> {
4057 let saved_range = self.current_source_range;
4059
4060 self.enter_function(name, parameters)?;
4062 self.current_code_info()
4063 .flags
4064 .set(bytecode::CodeFlags::COROUTINE, is_async);
4065
4066 let prev_ctx = self.ctx;
4068 self.ctx = CompileContext {
4069 loop_data: None,
4070 in_class: prev_ctx.in_class,
4071 func: if is_async {
4072 FunctionContext::AsyncFunction
4073 } else {
4074 FunctionContext::Function
4075 },
4076 in_async_scope: is_async,
4078 };
4079
4080 self.set_qualname();
4082
4083 let is_gen = is_async || self.current_symbol_table().is_generator;
4085 let stop_iteration_block = if is_gen {
4086 let handler_block = self.new_block();
4087 emit!(
4088 self,
4089 PseudoInstruction::SetupCleanup {
4090 delta: handler_block
4091 }
4092 );
4093 self.set_no_location();
4094 self.push_fblock(FBlockType::StopIteration, handler_block, handler_block)?;
4095 Some(handler_block)
4096 } else {
4097 None
4098 };
4099
4100 let (doc_str, body) = split_doc(body, &self.opts);
4102 if let Some(doc) = &doc_str {
4103 self.current_code_info()
4105 .metadata
4106 .consts
4107 .insert_full(ConstantData::Str {
4108 value: doc.to_string().into(),
4109 });
4110 self.current_code_info().flags |= bytecode::CodeFlags::HAS_DOCSTRING;
4111 }
4112 self.compile_statements(body)?;
4114
4115 match body.last() {
4120 Some(ast::Stmt::Return(_)) => {}
4121 _ => {
4122 self.emit_return_const(ConstantData::None);
4123 }
4124 }
4125 if self.current_code_info().metadata.consts.is_empty() {
4127 self.arg_constant(ConstantData::None);
4128 }
4129
4130 if let Some(handler_block) = stop_iteration_block {
4132 emit!(self, PseudoInstruction::PopBlock);
4133 self.set_no_location();
4134 self.pop_fblock(FBlockType::StopIteration);
4135 self.switch_to_block(handler_block);
4136 emit!(
4137 self,
4138 Instruction::CallIntrinsic1 {
4139 func: oparg::IntrinsicFunction1::StopIterationError
4140 }
4141 );
4142 self.set_no_location();
4143 emit!(self, Instruction::Reraise { depth: 1u32 });
4144 self.set_no_location();
4145 }
4146
4147 let code = self.exit_scope();
4149 self.ctx = prev_ctx;
4150
4151 self.set_source_range(saved_range);
4152
4153 self.make_closure(code, funcflags)?;
4155
4156 Ok(())
4160 }
4161
4162 fn compile_annotations_closure(
4166 &mut self,
4167 func_name: &str,
4168 parameters: &ast::Parameters,
4169 returns: Option<&ast::Expr>,
4170 ) -> CompileResult<bool> {
4171 let Some(saved_ctx) = self.enter_annotation_scope(func_name)? else {
4173 return Ok(false);
4174 };
4175
4176 let parameters_iter = core::iter::empty()
4178 .chain(¶meters.posonlyargs)
4179 .chain(¶meters.args)
4180 .chain(¶meters.kwonlyargs)
4181 .map(|x| &x.parameter)
4182 .chain(parameters.vararg.as_deref())
4183 .chain(parameters.kwarg.as_deref());
4184
4185 let num_annotations: u32 =
4186 u32::try_from(parameters_iter.filter(|p| p.annotation.is_some()).count())
4187 .expect("too many annotations")
4188 + if returns.is_some() { 1 } else { 0 };
4189
4190 let parameters_iter = core::iter::empty()
4192 .chain(¶meters.posonlyargs)
4193 .chain(¶meters.args)
4194 .chain(¶meters.kwonlyargs)
4195 .map(|x| &x.parameter)
4196 .chain(parameters.vararg.as_deref())
4197 .chain(parameters.kwarg.as_deref());
4198
4199 for param in parameters_iter {
4200 if let Some(annotation) = ¶m.annotation {
4201 self.emit_load_const(ConstantData::Str {
4202 value: self.mangle(param.name.as_str()).into_owned().into(),
4203 });
4204 self.compile_annotation(annotation)?;
4205 }
4206 }
4207
4208 if let Some(annotation) = returns {
4210 self.emit_load_const(ConstantData::Str {
4211 value: "return".into(),
4212 });
4213 self.compile_annotation(annotation)?;
4214 }
4215
4216 emit!(
4218 self,
4219 Instruction::BuildMap {
4220 count: num_annotations,
4221 }
4222 );
4223 emit!(self, Instruction::ReturnValue);
4224
4225 let annotate_code = self.exit_annotation_scope(saved_ctx);
4227
4228 self.make_closure(annotate_code, bytecode::MakeFunctionFlags::new())?;
4230
4231 Ok(true)
4232 }
4233
4234 fn collect_simple_annotations(body: &[ast::Stmt]) -> Vec<(&str, &ast::Expr)> {
4239 fn walk<'a>(stmts: &'a [ast::Stmt], out: &mut Vec<(&'a str, &'a ast::Expr)>) {
4240 for stmt in stmts {
4241 match stmt {
4242 ast::Stmt::AnnAssign(ast::StmtAnnAssign {
4243 target,
4244 annotation,
4245 simple,
4246 ..
4247 }) if *simple && matches!(target.as_ref(), ast::Expr::Name(_)) => {
4248 if let ast::Expr::Name(ast::ExprName { id, .. }) = target.as_ref() {
4249 out.push((id.as_str(), annotation.as_ref()));
4250 }
4251 }
4252 ast::Stmt::If(ast::StmtIf {
4253 body,
4254 elif_else_clauses,
4255 ..
4256 }) => {
4257 walk(body, out);
4258 for clause in elif_else_clauses {
4259 walk(&clause.body, out);
4260 }
4261 }
4262 ast::Stmt::For(ast::StmtFor { body, orelse, .. })
4263 | ast::Stmt::While(ast::StmtWhile { body, orelse, .. }) => {
4264 walk(body, out);
4265 walk(orelse, out);
4266 }
4267 ast::Stmt::With(ast::StmtWith { body, .. }) => walk(body, out),
4268 ast::Stmt::Try(ast::StmtTry {
4269 body,
4270 handlers,
4271 orelse,
4272 finalbody,
4273 ..
4274 }) => {
4275 walk(body, out);
4276 for handler in handlers {
4277 let ast::ExceptHandler::ExceptHandler(
4278 ast::ExceptHandlerExceptHandler { body, .. },
4279 ) = handler;
4280 walk(body, out);
4281 }
4282 walk(orelse, out);
4283 walk(finalbody, out);
4284 }
4285 ast::Stmt::Match(ast::StmtMatch { cases, .. }) => {
4286 for case in cases {
4287 walk(&case.body, out);
4288 }
4289 }
4290 _ => {}
4291 }
4292 }
4293 }
4294 let mut annotations = Vec::new();
4295 walk(body, &mut annotations);
4296 annotations
4297 }
4298
4299 fn compile_module_annotate(&mut self, body: &[ast::Stmt]) -> CompileResult<bool> {
4302 let annotations = Self::collect_simple_annotations(body);
4304
4305 if annotations.is_empty() {
4306 return Ok(false);
4307 }
4308
4309 let has_conditional = self.current_symbol_table().has_conditional_annotations;
4311
4312 let parent_scope_type = self.current_symbol_table().typ;
4314 if !self.push_current_annotation_symbol_table() {
4316 return Ok(false);
4317 }
4318
4319 let saved_ctx = self.ctx;
4321 self.ctx = CompileContext {
4322 loop_data: None,
4323 in_class: saved_ctx.in_class,
4324 func: FunctionContext::Function,
4325 in_async_scope: false,
4326 };
4327
4328 let key = self.symbol_table_stack.len() - 1;
4330 let lineno = self.get_source_line_number().get();
4331 self.enter_scope(
4332 "__annotate__",
4333 CompilerScope::Annotation,
4334 key,
4335 lineno.to_u32(),
4336 )?;
4337
4338 self.current_code_info()
4340 .metadata
4341 .varnames
4342 .insert("format".to_owned());
4343
4344 self.emit_format_validation()?;
4346
4347 if has_conditional {
4348 emit!(self, Instruction::BuildMap { count: 0 });
4351
4352 for (idx, (name, annotation)) in annotations.iter().enumerate() {
4354 let not_set_block = self.new_block();
4356
4357 self.emit_load_const(ConstantData::Integer { value: idx.into() });
4359 if parent_scope_type == CompilerScope::Class {
4362 let idx = self.get_free_var_index("__conditional_annotations__")?;
4363 emit!(self, Instruction::LoadDeref { i: idx });
4364 } else {
4365 let cond_annotations_name = self.name("__conditional_annotations__");
4366 self.emit_load_global(cond_annotations_name, false);
4367 }
4368 emit!(
4370 self,
4371 Instruction::ContainsOp {
4372 invert: bytecode::Invert::No
4373 }
4374 );
4375 emit!(
4377 self,
4378 Instruction::PopJumpIfFalse {
4379 delta: not_set_block
4380 }
4381 );
4382
4383 self.compile_annotation(annotation)?;
4385 emit!(self, Instruction::Copy { i: 2 });
4387 self.emit_load_const(ConstantData::Str {
4389 value: self.mangle(name).into_owned().into(),
4390 });
4391 emit!(self, Instruction::StoreSubscr);
4393
4394 self.switch_to_block(not_set_block);
4396 }
4397
4398 emit!(self, Instruction::ReturnValue);
4400 } else {
4401 let num_annotations = u32::try_from(annotations.len()).expect("too many annotations");
4403
4404 for (name, annotation) in annotations {
4406 self.emit_load_const(ConstantData::Str {
4407 value: self.mangle(name).into_owned().into(),
4408 });
4409 self.compile_annotation(annotation)?;
4410 }
4411
4412 emit!(
4414 self,
4415 Instruction::BuildMap {
4416 count: num_annotations,
4417 }
4418 );
4419 emit!(self, Instruction::ReturnValue);
4420 }
4421
4422 let annotation_table = self.pop_symbol_table();
4424 self.symbol_table_stack
4426 .last_mut()
4427 .expect("no module symbol table")
4428 .annotation_block = Some(Box::new(annotation_table));
4429 self.ctx = saved_ctx;
4431 let pop = self.code_stack.pop();
4433 let annotate_code = unwrap_internal(
4434 self,
4435 compiler_unwrap_option(self, pop).finalize_code(&self.opts),
4436 );
4437
4438 self.make_closure(annotate_code, bytecode::MakeFunctionFlags::new())?;
4440
4441 let name = if parent_scope_type == CompilerScope::Class {
4443 "__annotate_func__"
4444 } else {
4445 "__annotate__"
4446 };
4447 self.store_name(name)?;
4448
4449 Ok(true)
4450 }
4451
4452 #[allow(clippy::too_many_arguments)]
4454 fn compile_function_def(
4455 &mut self,
4456 name: &str,
4457 parameters: &ast::Parameters,
4458 body: &[ast::Stmt],
4459 decorator_list: &[ast::Decorator],
4460 returns: Option<&ast::Expr>, is_async: bool,
4462 type_params: Option<&ast::TypeParams>,
4463 ) -> CompileResult<()> {
4464 let def_source_range = self.current_source_range;
4467
4468 self.prepare_decorators(decorator_list)?;
4469
4470 let funcflags = self.compile_default_arguments(parameters)?;
4472
4473 self.set_source_range(def_source_range);
4476
4477 let is_generic = type_params.is_some();
4478 let mut num_typeparam_args = 0;
4479
4480 let saved_ctx = self.ctx;
4482
4483 if is_generic {
4484 if funcflags.contains(&bytecode::MakeFunctionFlag::Defaults) {
4486 num_typeparam_args += 1;
4487 }
4488 if funcflags.contains(&bytecode::MakeFunctionFlag::KwOnlyDefaults) {
4489 num_typeparam_args += 1;
4490 }
4491
4492 let type_params_name = format!("<generic parameters of {name}>");
4494 self.push_output(
4495 bytecode::CodeFlags::OPTIMIZED | bytecode::CodeFlags::NEWLOCALS,
4496 0,
4497 num_typeparam_args as u32,
4498 0,
4499 type_params_name,
4500 )?;
4501
4502 self.ctx = CompileContext {
4504 loop_data: None,
4505 in_class: saved_ctx.in_class,
4506 func: FunctionContext::Function,
4507 in_async_scope: false,
4508 };
4509
4510 let current_info = self.current_code_info();
4513 if funcflags.contains(&bytecode::MakeFunctionFlag::Defaults) {
4514 current_info
4515 .metadata
4516 .varnames
4517 .insert(".defaults".to_owned());
4518 }
4519 if funcflags.contains(&bytecode::MakeFunctionFlag::KwOnlyDefaults) {
4520 current_info
4521 .metadata
4522 .varnames
4523 .insert(".kwdefaults".to_owned());
4524 }
4525
4526 self.compile_type_params(type_params.unwrap())?;
4528
4529 for i in 0..num_typeparam_args {
4531 let var_num = oparg::VarNum::from(i as u32);
4532 emit!(self, Instruction::LoadFast { var_num });
4533 }
4534 }
4535
4536 let mut annotations_flag = bytecode::MakeFunctionFlags::new();
4538 if self.compile_annotations_closure(name, parameters, returns)? {
4539 annotations_flag.insert(bytecode::MakeFunctionFlag::Annotate);
4540 }
4541
4542 let final_funcflags = funcflags | annotations_flag;
4544 self.compile_function_body(name, parameters, body, is_async, final_funcflags)?;
4545
4546 if is_generic {
4548 emit!(self, Instruction::Swap { i: 2 });
4551
4552 emit!(
4554 self,
4555 Instruction::CallIntrinsic2 {
4556 func: bytecode::IntrinsicFunction2::SetFunctionTypeParams,
4557 }
4558 );
4559
4560 emit!(self, Instruction::ReturnValue);
4562
4563 self.current_code_info().metadata.argcount = num_typeparam_args as u32;
4565
4566 let type_params_code = self.exit_scope();
4568 self.ctx = saved_ctx;
4569
4570 self.make_closure(type_params_code, bytecode::MakeFunctionFlags::new())?;
4572
4573 if num_typeparam_args > 0 {
4579 match num_typeparam_args {
4580 1 => {
4581 emit!(self, Instruction::Swap { i: 2 }); emit!(self, Instruction::PushNull); emit!(self, Instruction::Swap { i: 2 }); }
4586 2 => {
4587 emit!(self, Instruction::Swap { i: 3 }); emit!(self, Instruction::Swap { i: 2 }); emit!(self, Instruction::PushNull); emit!(self, Instruction::Swap { i: 3 }); emit!(self, Instruction::Swap { i: 2 }); }
4594 _ => unreachable!("only defaults and kwdefaults are supported"),
4595 }
4596 emit!(
4597 self,
4598 Instruction::Call {
4599 argc: num_typeparam_args as u32
4600 }
4601 );
4602 } else {
4603 emit!(self, Instruction::PushNull);
4605 emit!(self, Instruction::Call { argc: 0 });
4607 }
4608 }
4609
4610 self.apply_decorators(decorator_list);
4612
4613 self.store_name(name)?;
4615
4616 Ok(())
4617 }
4618
4619 fn get_ref_type(&self, name: &str) -> Result<SymbolScope, CodegenErrorType> {
4622 let table = self.symbol_table_stack.last().unwrap();
4623
4624 if table.typ == CompilerScope::Class
4628 && (name == "__class__"
4629 || name == "__classdict__"
4630 || name == "__conditional_annotations__")
4631 {
4632 return Ok(SymbolScope::Cell);
4633 }
4634 match table.lookup(name) {
4635 Some(symbol) => match symbol.scope {
4636 SymbolScope::Cell => Ok(SymbolScope::Cell),
4637 SymbolScope::Free => Ok(SymbolScope::Free),
4638 _ if symbol.flags.contains(SymbolFlags::FREE_CLASS) => Ok(SymbolScope::Free),
4639 _ => Err(CodegenErrorType::SyntaxError(format!(
4640 "get_ref_type: invalid scope for '{name}'"
4641 ))),
4642 },
4643 None => Err(CodegenErrorType::SyntaxError(format!(
4644 "get_ref_type: cannot find symbol '{name}'"
4645 ))),
4646 }
4647 }
4648
4649 fn make_closure(
4652 &mut self,
4653 code: CodeObject,
4654 flags: bytecode::MakeFunctionFlags,
4655 ) -> CompileResult<()> {
4656 let has_freevars = !code.freevars.is_empty();
4658 if has_freevars {
4659 for var in &code.freevars {
4662 let ref_type = self.get_ref_type(var).map_err(|e| self.error(e))?;
4670
4671 let parent_code = self.code_stack.last().unwrap();
4673 let cellvars_len = parent_code.metadata.cellvars.len();
4674
4675 let idx = match ref_type {
4677 SymbolScope::Cell => parent_code
4678 .metadata
4679 .cellvars
4680 .get_index_of(var)
4681 .or_else(|| {
4682 parent_code
4683 .metadata
4684 .freevars
4685 .get_index_of(var)
4686 .map(|i| i + cellvars_len)
4687 })
4688 .ok_or_else(|| {
4689 self.error(CodegenErrorType::SyntaxError(format!(
4690 "compiler_make_closure: cannot find '{var}' in parent vars",
4691 )))
4692 })?,
4693 SymbolScope::Free => parent_code
4694 .metadata
4695 .freevars
4696 .get_index_of(var)
4697 .map(|i| i + cellvars_len)
4698 .or_else(|| parent_code.metadata.cellvars.get_index_of(var))
4699 .ok_or_else(|| {
4700 self.error(CodegenErrorType::SyntaxError(format!(
4701 "compiler_make_closure: cannot find '{var}' in parent vars",
4702 )))
4703 })?,
4704 _ => {
4705 return Err(self.error(CodegenErrorType::SyntaxError(format!(
4706 "compiler_make_closure: unexpected ref_type {ref_type:?} for '{var}'",
4707 ))));
4708 }
4709 };
4710
4711 emit!(self, PseudoInstruction::LoadClosure { i: idx.to_u32() });
4712 }
4713
4714 emit!(
4716 self,
4717 Instruction::BuildTuple {
4718 count: code.freevars.len().to_u32(),
4719 }
4720 );
4721 }
4722
4723 self.emit_load_const(ConstantData::Code {
4725 code: Box::new(code),
4726 });
4727
4728 emit!(self, Instruction::MakeFunction);
4730
4731 if has_freevars {
4736 emit!(
4737 self,
4738 Instruction::SetFunctionAttribute {
4739 flag: bytecode::MakeFunctionFlag::Closure
4740 }
4741 );
4742 }
4743
4744 if flags.contains(&bytecode::MakeFunctionFlag::Annotations) {
4746 emit!(
4747 self,
4748 Instruction::SetFunctionAttribute {
4749 flag: bytecode::MakeFunctionFlag::Annotations
4750 }
4751 );
4752 }
4753
4754 if flags.contains(&bytecode::MakeFunctionFlag::Annotate) {
4756 emit!(
4757 self,
4758 Instruction::SetFunctionAttribute {
4759 flag: bytecode::MakeFunctionFlag::Annotate
4760 }
4761 );
4762 }
4763
4764 if flags.contains(&bytecode::MakeFunctionFlag::KwOnlyDefaults) {
4766 emit!(
4767 self,
4768 Instruction::SetFunctionAttribute {
4769 flag: bytecode::MakeFunctionFlag::KwOnlyDefaults
4770 }
4771 );
4772 }
4773
4774 if flags.contains(&bytecode::MakeFunctionFlag::Defaults) {
4776 emit!(
4777 self,
4778 Instruction::SetFunctionAttribute {
4779 flag: bytecode::MakeFunctionFlag::Defaults
4780 }
4781 );
4782 }
4783
4784 if flags.contains(&bytecode::MakeFunctionFlag::TypeParams) {
4786 emit!(
4787 self,
4788 Instruction::SetFunctionAttribute {
4789 flag: bytecode::MakeFunctionFlag::TypeParams
4790 }
4791 );
4792 }
4793
4794 Ok(())
4795 }
4796
4797 fn collect_static_attributes(body: &[ast::Stmt], attrs: Option<&mut IndexSet<String>>) {
4800 let Some(attrs) = attrs else { return };
4801 for stmt in body {
4802 let f = match stmt {
4803 ast::Stmt::FunctionDef(f) => f,
4804 _ => continue,
4805 };
4806 let has_special_decorator = f.decorator_list.iter().any(|d| {
4808 matches!(&d.expression, ast::Expr::Name(n)
4809 if n.id.as_str() == "staticmethod" || n.id.as_str() == "classmethod")
4810 });
4811 if has_special_decorator {
4812 continue;
4813 }
4814 let fname = f.name.as_str();
4816 if fname == "__init_subclass__" || fname == "__class_getitem__" {
4817 continue;
4818 }
4819 if fname == "__new__" {
4821 Self::scan_store_attrs(&f.body, "self", attrs);
4822 continue;
4823 }
4824 let first_param = f
4825 .parameters
4826 .posonlyargs
4827 .first()
4828 .or(f.parameters.args.first())
4829 .map(|p| &p.parameter.name);
4830 let Some(self_name) = first_param else {
4831 continue;
4832 };
4833 Self::scan_store_attrs(&f.body, self_name.as_str(), attrs);
4834 }
4835 }
4836
4837 fn scan_target_for_attrs(target: &ast::Expr, name: &str, attrs: &mut IndexSet<String>) {
4839 match target {
4840 ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) => {
4841 if let ast::Expr::Name(n) = value.as_ref()
4842 && n.id.as_str() == name
4843 {
4844 attrs.insert(attr.to_string());
4845 }
4846 }
4847 ast::Expr::Tuple(t) => {
4848 for elt in &t.elts {
4849 Self::scan_target_for_attrs(elt, name, attrs);
4850 }
4851 }
4852 ast::Expr::List(l) => {
4853 for elt in &l.elts {
4854 Self::scan_target_for_attrs(elt, name, attrs);
4855 }
4856 }
4857 ast::Expr::Starred(s) => {
4858 Self::scan_target_for_attrs(&s.value, name, attrs);
4859 }
4860 _ => {}
4861 }
4862 }
4863
4864 fn scan_store_attrs(stmts: &[ast::Stmt], name: &str, attrs: &mut IndexSet<String>) {
4866 for stmt in stmts {
4867 match stmt {
4868 ast::Stmt::Assign(a) => {
4869 for target in &a.targets {
4870 Self::scan_target_for_attrs(target, name, attrs);
4871 }
4872 }
4873 ast::Stmt::AnnAssign(a) => {
4874 Self::scan_target_for_attrs(&a.target, name, attrs);
4875 }
4876 ast::Stmt::AugAssign(a) => {
4877 if let ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) =
4878 a.target.as_ref()
4879 && let ast::Expr::Name(n) = value.as_ref()
4880 && n.id.as_str() == name
4881 {
4882 attrs.insert(attr.to_string());
4883 }
4884 }
4885 ast::Stmt::If(s) => {
4886 Self::scan_store_attrs(&s.body, name, attrs);
4887 for clause in &s.elif_else_clauses {
4888 Self::scan_store_attrs(&clause.body, name, attrs);
4889 }
4890 }
4891 ast::Stmt::For(s) => {
4892 Self::scan_store_attrs(&s.body, name, attrs);
4893 Self::scan_store_attrs(&s.orelse, name, attrs);
4894 }
4895 ast::Stmt::While(s) => {
4896 Self::scan_store_attrs(&s.body, name, attrs);
4897 Self::scan_store_attrs(&s.orelse, name, attrs);
4898 }
4899 ast::Stmt::Try(s) => {
4900 Self::scan_store_attrs(&s.body, name, attrs);
4901 for handler in &s.handlers {
4902 let ast::ExceptHandler::ExceptHandler(h) = handler;
4903 Self::scan_store_attrs(&h.body, name, attrs);
4904 }
4905 Self::scan_store_attrs(&s.orelse, name, attrs);
4906 Self::scan_store_attrs(&s.finalbody, name, attrs);
4907 }
4908 ast::Stmt::With(s) => {
4909 Self::scan_store_attrs(&s.body, name, attrs);
4910 }
4911 ast::Stmt::Match(s) => {
4912 for case in &s.cases {
4913 Self::scan_store_attrs(&case.body, name, attrs);
4914 }
4915 }
4916 _ => {}
4917 }
4918 }
4919 }
4920
4921 fn find_ann(body: &[ast::Stmt]) -> bool {
4923 for statement in body {
4924 let res = match &statement {
4925 ast::Stmt::AnnAssign(_) => true,
4926 ast::Stmt::For(ast::StmtFor { body, orelse, .. }) => {
4927 Self::find_ann(body) || Self::find_ann(orelse)
4928 }
4929 ast::Stmt::If(ast::StmtIf {
4930 body,
4931 elif_else_clauses,
4932 ..
4933 }) => {
4934 Self::find_ann(body)
4935 || elif_else_clauses.iter().any(|x| Self::find_ann(&x.body))
4936 }
4937 ast::Stmt::While(ast::StmtWhile { body, orelse, .. }) => {
4938 Self::find_ann(body) || Self::find_ann(orelse)
4939 }
4940 ast::Stmt::With(ast::StmtWith { body, .. }) => Self::find_ann(body),
4941 ast::Stmt::Match(ast::StmtMatch { cases, .. }) => {
4942 cases.iter().any(|case| Self::find_ann(&case.body))
4943 }
4944 ast::Stmt::Try(ast::StmtTry {
4945 body,
4946 handlers,
4947 orelse,
4948 finalbody,
4949 ..
4950 }) => {
4951 Self::find_ann(body)
4952 || handlers.iter().any(|h| {
4953 let ast::ExceptHandler::ExceptHandler(
4954 ast::ExceptHandlerExceptHandler { body, .. },
4955 ) = h;
4956 Self::find_ann(body)
4957 })
4958 || Self::find_ann(orelse)
4959 || Self::find_ann(finalbody)
4960 }
4961 _ => false,
4962 };
4963 if res {
4964 return true;
4965 }
4966 }
4967 false
4968 }
4969
4970 fn compile_class_body(
4973 &mut self,
4974 name: &str,
4975 body: &[ast::Stmt],
4976 type_params: Option<&ast::TypeParams>,
4977 firstlineno: u32,
4978 ) -> CompileResult<CodeObject> {
4979 let key = self.symbol_table_stack.len();
4981 self.push_symbol_table()?;
4982 self.enter_scope(name, CompilerScope::Class, key, firstlineno)?;
4983
4984 let qualname = self.set_qualname();
4986
4987 self.code_stack.last_mut().unwrap().private = Some(name.to_owned());
4989
4990 let (doc_str, body) = split_doc(body, &self.opts);
4992
4993 let dunder_name = self.name("__name__");
4995 emit!(self, Instruction::LoadName { namei: dunder_name });
4996 let dunder_module = self.name("__module__");
4997 emit!(
4998 self,
4999 Instruction::StoreName {
5000 namei: dunder_module
5001 }
5002 );
5003
5004 self.emit_load_const(ConstantData::Str {
5006 value: qualname.into(),
5007 });
5008 let qualname_name = self.name("__qualname__");
5009 emit!(
5010 self,
5011 Instruction::StoreName {
5012 namei: qualname_name
5013 }
5014 );
5015
5016 self.emit_load_const(ConstantData::Integer {
5018 value: BigInt::from(firstlineno),
5019 });
5020 let firstlineno_name = self.name("__firstlineno__");
5021 emit!(
5022 self,
5023 Instruction::StoreName {
5024 namei: firstlineno_name
5025 }
5026 );
5027
5028 if self.current_symbol_table().needs_classdict {
5030 emit!(self, Instruction::LoadLocals);
5031 let classdict_idx = self.get_cell_var_index("__classdict__")?;
5032 emit!(self, Instruction::StoreDeref { i: classdict_idx });
5033 }
5034
5035 if let Some(doc) = doc_str {
5037 self.emit_load_const(ConstantData::Str { value: doc.into() });
5038 let doc_name = self.name("__doc__");
5039 emit!(self, Instruction::StoreName { namei: doc_name });
5040 }
5041
5042 if type_params.is_some() {
5044 let dot_type_params = self.name(".type_params");
5046 emit!(
5047 self,
5048 Instruction::LoadName {
5049 namei: dot_type_params
5050 }
5051 );
5052
5053 let dunder_type_params = self.name("__type_params__");
5055 emit!(
5056 self,
5057 Instruction::StoreName {
5058 namei: dunder_type_params
5059 }
5060 );
5061 }
5062
5063 if Self::find_ann(body) {
5065 if self.future_annotations {
5066 emit!(self, Instruction::SetupAnnotations);
5068 } else {
5069 if self.current_symbol_table().has_conditional_annotations {
5071 emit!(self, Instruction::BuildSet { count: 0 });
5072 self.store_name("__conditional_annotations__")?;
5073 }
5074
5075 self.compile_module_annotate(body)?;
5077 }
5078 }
5079
5080 Self::collect_static_attributes(
5082 body,
5083 self.code_stack
5084 .last_mut()
5085 .unwrap()
5086 .static_attributes
5087 .as_mut(),
5088 );
5089
5090 self.compile_statements(body)?;
5092
5093 let classcell_idx = self
5095 .code_stack
5096 .last_mut()
5097 .unwrap()
5098 .metadata
5099 .cellvars
5100 .iter()
5101 .position(|var| *var == "__class__");
5102
5103 {
5105 let mut attrs: Vec<String> = self
5106 .code_stack
5107 .last()
5108 .unwrap()
5109 .static_attributes
5110 .as_ref()
5111 .map(|s| s.iter().cloned().collect())
5112 .unwrap_or_default();
5113 attrs.sort();
5114 self.emit_load_const(ConstantData::Tuple {
5115 elements: attrs
5116 .into_iter()
5117 .map(|s| ConstantData::Str { value: s.into() })
5118 .collect(),
5119 });
5120 let static_attrs_name = self.name("__static_attributes__");
5121 emit!(
5122 self,
5123 Instruction::StoreName {
5124 namei: static_attrs_name
5125 }
5126 );
5127 }
5128
5129 if self.current_symbol_table().needs_classdict {
5131 let classdict_idx = u32::from(self.get_cell_var_index("__classdict__")?);
5132 emit!(self, PseudoInstruction::LoadClosure { i: classdict_idx });
5133 let classdictcell = self.name("__classdictcell__");
5134 emit!(
5135 self,
5136 Instruction::StoreName {
5137 namei: classdictcell
5138 }
5139 );
5140 }
5141
5142 if let Some(classcell_idx) = classcell_idx {
5143 emit!(
5144 self,
5145 PseudoInstruction::LoadClosure {
5146 i: classcell_idx.to_u32()
5147 }
5148 );
5149 emit!(self, Instruction::Copy { i: 1 });
5150 let classcell = self.name("__classcell__");
5151 emit!(self, Instruction::StoreName { namei: classcell });
5152 } else {
5153 self.emit_load_const(ConstantData::None);
5154 }
5155
5156 self.emit_return_value();
5158
5159 Ok(self.exit_scope())
5161 }
5162
5163 fn compile_class_def(
5164 &mut self,
5165 name: &str,
5166 body: &[ast::Stmt],
5167 decorator_list: &[ast::Decorator],
5168 type_params: Option<&ast::TypeParams>,
5169 arguments: Option<&ast::Arguments>,
5170 ) -> CompileResult<()> {
5171 self.prepare_decorators(decorator_list)?;
5172
5173 let is_generic = type_params.is_some();
5174 let firstlineno = self.get_source_line_number().get().to_u32();
5175
5176 let saved_ctx = self.ctx;
5178
5179 if is_generic {
5181 let type_params_name = format!("<generic parameters of {name}>");
5182 self.push_output(
5183 bytecode::CodeFlags::OPTIMIZED | bytecode::CodeFlags::NEWLOCALS,
5184 0,
5185 0,
5186 0,
5187 type_params_name,
5188 )?;
5189
5190 self.code_stack.last_mut().unwrap().private = Some(name.to_owned());
5192
5193 self.ctx = CompileContext {
5195 loop_data: None,
5196 in_class: saved_ctx.in_class,
5197 func: FunctionContext::Function,
5198 in_async_scope: false,
5199 };
5200
5201 self.compile_type_params(type_params.unwrap())?;
5203 let dot_type_params = self.name(".type_params");
5204 emit!(
5205 self,
5206 Instruction::StoreName {
5207 namei: dot_type_params
5208 }
5209 );
5210 }
5211
5212 let prev_ctx = self.ctx;
5214 self.ctx = CompileContext {
5215 func: FunctionContext::NoFunction,
5216 in_class: true,
5217 loop_data: None,
5218 in_async_scope: false,
5219 };
5220 let class_code = self.compile_class_body(name, body, type_params, firstlineno)?;
5221 self.ctx = prev_ctx;
5222
5223 if is_generic {
5225 let dot_type_params = self.name(".type_params");
5227 let dot_generic_base = self.name(".generic_base");
5228
5229 emit!(
5231 self,
5232 Instruction::LoadName {
5233 namei: dot_type_params
5234 }
5235 );
5236 emit!(
5237 self,
5238 Instruction::CallIntrinsic1 {
5239 func: bytecode::IntrinsicFunction1::SubscriptGeneric
5240 }
5241 );
5242 emit!(
5243 self,
5244 Instruction::StoreName {
5245 namei: dot_generic_base
5246 }
5247 );
5248
5249 emit!(self, Instruction::LoadBuildClass);
5251 emit!(self, Instruction::PushNull);
5252
5253 let mut func_flags = bytecode::MakeFunctionFlags::new();
5255 emit!(
5256 self,
5257 Instruction::LoadName {
5258 namei: dot_type_params
5259 }
5260 );
5261 func_flags.insert(bytecode::MakeFunctionFlag::TypeParams);
5262
5263 self.make_closure(class_code, func_flags)?;
5265 self.emit_load_const(ConstantData::Str { value: name.into() });
5266
5267 let has_starred = arguments.is_some_and(|args| {
5270 args.args
5271 .iter()
5272 .any(|arg| matches!(arg, ast::Expr::Starred(_)))
5273 });
5274 let has_double_star =
5275 arguments.is_some_and(|args| args.keywords.iter().any(|kw| kw.arg.is_none()));
5276
5277 if has_starred || has_double_star {
5278 emit!(self, Instruction::BuildList { count: 2 });
5284
5285 if let Some(arguments) = arguments {
5287 for arg in &arguments.args {
5288 if let ast::Expr::Starred(ast::ExprStarred { value, .. }) = arg {
5289 self.compile_expression(value)?;
5291 emit!(self, Instruction::ListExtend { i: 1 });
5292 } else {
5293 self.compile_expression(arg)?;
5295 emit!(self, Instruction::ListAppend { i: 1 });
5296 }
5297 }
5298 }
5299
5300 emit!(
5302 self,
5303 Instruction::LoadName {
5304 namei: dot_generic_base
5305 }
5306 );
5307 emit!(self, Instruction::ListAppend { i: 1 });
5308
5309 emit!(
5311 self,
5312 Instruction::CallIntrinsic1 {
5313 func: IntrinsicFunction1::ListToTuple
5314 }
5315 );
5316
5317 if arguments.is_some_and(|args| !args.keywords.is_empty()) {
5319 self.compile_keywords(&arguments.unwrap().keywords)?;
5320 } else {
5321 emit!(self, Instruction::PushNull);
5322 }
5323 emit!(self, Instruction::CallFunctionEx);
5324 } else {
5325 let base_count = if let Some(arguments) = arguments {
5328 for arg in &arguments.args {
5329 self.compile_expression(arg)?;
5330 }
5331 arguments.args.len()
5332 } else {
5333 0
5334 };
5335
5336 emit!(
5338 self,
5339 Instruction::LoadName {
5340 namei: dot_generic_base
5341 }
5342 );
5343
5344 let nargs = 2 + u32::try_from(base_count).expect("too many base classes") + 1;
5345
5346 if let Some(arguments) = arguments
5348 && !arguments.keywords.is_empty()
5349 {
5350 let mut kwarg_names = vec![];
5351 for keyword in &arguments.keywords {
5352 let name = keyword.arg.as_ref().expect(
5353 "keyword argument name must be set (no **kwargs in this branch)",
5354 );
5355 kwarg_names.push(ConstantData::Str {
5356 value: name.as_str().into(),
5357 });
5358 self.compile_expression(&keyword.value)?;
5359 }
5360 self.emit_load_const(ConstantData::Tuple {
5361 elements: kwarg_names,
5362 });
5363 emit!(
5364 self,
5365 Instruction::CallKw {
5366 argc: nargs
5367 + u32::try_from(arguments.keywords.len())
5368 .expect("too many keyword arguments")
5369 }
5370 );
5371 } else {
5372 emit!(self, Instruction::Call { argc: nargs });
5373 }
5374 }
5375
5376 self.emit_return_value();
5378
5379 let type_params_code = self.exit_scope();
5381 self.ctx = saved_ctx;
5382
5383 self.make_closure(type_params_code, bytecode::MakeFunctionFlags::new())?;
5385 emit!(self, Instruction::PushNull);
5386 emit!(self, Instruction::Call { argc: 0 });
5387 } else {
5388 emit!(self, Instruction::LoadBuildClass);
5390 emit!(self, Instruction::PushNull);
5391
5392 self.make_closure(class_code, bytecode::MakeFunctionFlags::new())?;
5394 self.emit_load_const(ConstantData::Str { value: name.into() });
5395
5396 if let Some(arguments) = arguments {
5397 self.codegen_call_helper(2, arguments, self.current_source_range)?;
5398 } else {
5399 emit!(self, Instruction::Call { argc: 2 });
5400 }
5401 }
5402
5403 self.apply_decorators(decorator_list);
5405 self.store_name(name)
5406 }
5407
5408 fn compile_if(
5411 &mut self,
5412 test: &ast::Expr,
5413 body: &[ast::Stmt],
5414 elif_else_clauses: &[ast::ElifElseClause],
5415 ) -> CompileResult<()> {
5416 let constant = Self::expr_constant(test);
5417
5418 if constant == Some(false) {
5421 self.emit_nop();
5422 self.do_not_emit_bytecode += 1;
5423 self.compile_statements(body)?;
5424 self.do_not_emit_bytecode -= 1;
5425 match elif_else_clauses {
5427 [] => {}
5428 [first, rest @ ..] => {
5429 if let Some(elif_test) = &first.test {
5430 self.compile_if(elif_test, &first.body, rest)?;
5431 } else {
5432 self.compile_statements(&first.body)?;
5433 }
5434 }
5435 }
5436 return Ok(());
5437 }
5438
5439 if constant == Some(true) {
5442 self.emit_nop();
5443 self.compile_statements(body)?;
5444 self.do_not_emit_bytecode += 1;
5445 for clause in elif_else_clauses {
5446 if let Some(elif_test) = &clause.test {
5447 self.compile_expression(elif_test)?;
5448 }
5449 self.compile_statements(&clause.body)?;
5450 }
5451 self.do_not_emit_bytecode -= 1;
5452 return Ok(());
5453 }
5454
5455 match elif_else_clauses {
5457 [] => {
5459 let after_block = self.new_block();
5460 self.compile_jump_if(test, false, after_block)?;
5461 self.compile_statements(body)?;
5462 self.switch_to_block(after_block);
5463 }
5464 [rest @ .., tail] => {
5466 let after_block = self.new_block();
5467 let mut next_block = self.new_block();
5468
5469 self.compile_jump_if(test, false, next_block)?;
5470 self.compile_statements(body)?;
5471 emit!(self, PseudoInstruction::Jump { delta: after_block });
5472
5473 for clause in rest {
5474 self.switch_to_block(next_block);
5475 next_block = self.new_block();
5476 if let Some(test) = &clause.test {
5477 self.compile_jump_if(test, false, next_block)?;
5478 } else {
5479 unreachable!() }
5481 self.compile_statements(&clause.body)?;
5482 emit!(self, PseudoInstruction::Jump { delta: after_block });
5483 }
5484
5485 self.switch_to_block(next_block);
5486 if let Some(test) = &tail.test {
5487 self.compile_jump_if(test, false, after_block)?;
5488 }
5489 self.compile_statements(&tail.body)?;
5490 self.switch_to_block(after_block);
5491 }
5492 }
5493 Ok(())
5494 }
5495
5496 fn compile_while(
5497 &mut self,
5498 test: &ast::Expr,
5499 body: &[ast::Stmt],
5500 orelse: &[ast::Stmt],
5501 ) -> CompileResult<()> {
5502 self.enter_conditional_block();
5503
5504 let constant = Self::expr_constant(test);
5505
5506 if constant == Some(false) {
5509 self.emit_nop();
5510 let while_block = self.new_block();
5511 let after_block = self.new_block();
5512 self.push_fblock(FBlockType::WhileLoop, while_block, after_block)?;
5513 self.do_not_emit_bytecode += 1;
5514 self.compile_statements(body)?;
5515 self.do_not_emit_bytecode -= 1;
5516 self.pop_fblock(FBlockType::WhileLoop);
5517 self.compile_statements(orelse)?;
5518 self.leave_conditional_block();
5519 return Ok(());
5520 }
5521
5522 let while_block = self.new_block();
5523 let else_block = self.new_block();
5524 let after_block = self.new_block();
5525
5526 self.switch_to_block(while_block);
5527 self.push_fblock(FBlockType::WhileLoop, while_block, after_block)?;
5528
5529 if constant == Some(true) {
5531 self.emit_nop();
5532 } else {
5533 self.compile_jump_if(test, false, else_block)?;
5534 }
5535
5536 let was_in_loop = self.ctx.loop_data.replace((while_block, after_block));
5537 self.compile_statements(body)?;
5538 self.ctx.loop_data = was_in_loop;
5539 emit!(self, PseudoInstruction::Jump { delta: while_block });
5540 self.switch_to_block(else_block);
5541
5542 self.pop_fblock(FBlockType::WhileLoop);
5543 self.compile_statements(orelse)?;
5544 self.switch_to_block(after_block);
5545
5546 self.leave_conditional_block();
5547 Ok(())
5548 }
5549
5550 fn compile_with(
5551 &mut self,
5552 items: &[ast::WithItem],
5553 body: &[ast::Stmt],
5554 is_async: bool,
5555 ) -> CompileResult<()> {
5556 self.enter_conditional_block();
5557
5558 let with_range = self.current_source_range;
5586
5587 let Some((item, items)) = items.split_first() else {
5588 return Err(self.error(CodegenErrorType::EmptyWithItems));
5589 };
5590
5591 let exc_handler_block = self.new_block();
5592 let after_block = self.new_block();
5593
5594 self.compile_expression(&item.context_expr)?;
5596 self.set_source_range(with_range);
5597
5598 emit!(self, Instruction::Copy { i: 1 }); if is_async {
5602 if self.ctx.func != FunctionContext::AsyncFunction {
5603 return Err(self.error(CodegenErrorType::InvalidAsyncWith));
5604 }
5605 emit!(
5607 self,
5608 Instruction::LoadSpecial {
5609 method: SpecialMethod::AExit
5610 }
5611 ); emit!(self, Instruction::Swap { i: 2 }); emit!(self, Instruction::Swap { i: 3 }); emit!(
5615 self,
5616 Instruction::LoadSpecial {
5617 method: SpecialMethod::AEnter
5618 }
5619 ); emit!(self, Instruction::Call { argc: 0 }); emit!(self, Instruction::GetAwaitable { r#where: 1 });
5622 self.emit_load_const(ConstantData::None);
5623 let _ = self.compile_yield_from_sequence(true)?;
5624 } else {
5625 emit!(
5627 self,
5628 Instruction::LoadSpecial {
5629 method: SpecialMethod::Exit
5630 }
5631 ); emit!(self, Instruction::Swap { i: 2 }); emit!(self, Instruction::Swap { i: 3 }); emit!(
5635 self,
5636 Instruction::LoadSpecial {
5637 method: SpecialMethod::Enter
5638 }
5639 ); emit!(self, Instruction::Call { argc: 0 }); }
5642
5643 emit!(
5647 self,
5648 PseudoInstruction::SetupWith {
5649 delta: exc_handler_block
5650 }
5651 );
5652 self.push_fblock(
5653 if is_async {
5654 FBlockType::AsyncWith
5655 } else {
5656 FBlockType::With
5657 },
5658 exc_handler_block, after_block,
5660 )?;
5661
5662 match &item.optional_vars {
5664 Some(var) => {
5665 self.set_source_range(var.range());
5666 self.compile_store(var)?;
5667 }
5668 None => {
5669 emit!(self, Instruction::PopTop);
5670 }
5671 }
5672 if items.is_empty() {
5676 if body.is_empty() {
5677 return Err(self.error(CodegenErrorType::EmptyWithBody));
5678 }
5679 self.compile_statements(body)?;
5680 } else {
5681 self.set_source_range(with_range);
5682 self.compile_with(items, body, is_async)?;
5683 }
5684
5685 emit!(self, PseudoInstruction::PopBlock);
5687 self.pop_fblock(if is_async {
5688 FBlockType::AsyncWith
5689 } else {
5690 FBlockType::With
5691 });
5692
5693 self.set_source_range(with_range);
5697 self.emit_load_const(ConstantData::None);
5698 self.emit_load_const(ConstantData::None);
5699 self.emit_load_const(ConstantData::None);
5700 emit!(self, Instruction::Call { argc: 3 });
5701 if is_async {
5702 emit!(self, Instruction::GetAwaitable { r#where: 2 });
5703 self.emit_load_const(ConstantData::None);
5704 let _ = self.compile_yield_from_sequence(true)?;
5705 }
5706 emit!(self, Instruction::PopTop); emit!(self, PseudoInstruction::Jump { delta: after_block });
5708
5709 self.switch_to_block(exc_handler_block);
5713
5714 let cleanup_block = self.new_block();
5715 let suppress_block = self.new_block();
5716
5717 emit!(
5718 self,
5719 PseudoInstruction::SetupCleanup {
5720 delta: cleanup_block
5721 }
5722 );
5723 self.push_fblock(FBlockType::ExceptionHandler, exc_handler_block, after_block)?;
5724
5725 emit!(self, Instruction::PushExcInfo);
5726
5727 emit!(self, Instruction::WithExceptStart);
5730
5731 if is_async {
5732 emit!(self, Instruction::GetAwaitable { r#where: 2 });
5733 self.emit_load_const(ConstantData::None);
5734 let _ = self.compile_yield_from_sequence(true)?;
5735 }
5736
5737 emit!(self, Instruction::ToBool);
5738 emit!(
5739 self,
5740 Instruction::PopJumpIfTrue {
5741 delta: suppress_block
5742 }
5743 );
5744
5745 emit!(self, PseudoInstruction::PopBlock);
5746 self.pop_fblock(FBlockType::ExceptionHandler);
5747
5748 emit!(self, Instruction::Reraise { depth: 2 });
5749
5750 self.switch_to_block(suppress_block);
5753 emit!(self, Instruction::PopTop); emit!(self, Instruction::PopExcept); emit!(self, Instruction::PopTop); emit!(self, Instruction::PopTop); emit!(self, Instruction::PopTop); emit!(self, PseudoInstruction::Jump { delta: after_block });
5759
5760 self.switch_to_block(cleanup_block);
5771 emit!(self, Instruction::Copy { i: 3 });
5772 emit!(self, Instruction::PopExcept);
5773 emit!(self, Instruction::Reraise { depth: 1 });
5774
5775 self.switch_to_block(after_block);
5777
5778 self.leave_conditional_block();
5779 Ok(())
5780 }
5781
5782 fn compile_for(
5783 &mut self,
5784 target: &ast::Expr,
5785 iter: &ast::Expr,
5786 body: &[ast::Stmt],
5787 orelse: &[ast::Stmt],
5788 is_async: bool,
5789 ) -> CompileResult<()> {
5790 self.enter_conditional_block();
5791
5792 let for_block = self.new_block();
5794 let else_block = self.new_block();
5795 let after_block = self.new_block();
5796 let mut end_async_for_target = BlockIdx::NULL;
5797
5798 if !is_async
5802 && let ast::Expr::List(ast::ExprList { elts, .. }) = iter
5803 && !elts.iter().any(|e| matches!(e, ast::Expr::Starred(_)))
5804 {
5805 for elt in elts {
5806 self.compile_expression(elt)?;
5807 }
5808 emit!(
5809 self,
5810 Instruction::BuildTuple {
5811 count: u32::try_from(elts.len()).expect("too many elements"),
5812 }
5813 );
5814 } else {
5815 self.compile_expression(iter)?;
5816 }
5817
5818 if is_async {
5819 if self.ctx.func != FunctionContext::AsyncFunction {
5820 return Err(self.error(CodegenErrorType::InvalidAsyncFor));
5821 }
5822 emit!(self, Instruction::GetAIter);
5823
5824 self.switch_to_block(for_block);
5825
5826 self.push_fblock(FBlockType::ForLoop, for_block, after_block)?;
5828
5829 emit!(self, PseudoInstruction::SetupFinally { delta: else_block });
5831 emit!(self, Instruction::GetANext);
5832 self.emit_load_const(ConstantData::None);
5833 end_async_for_target = self.compile_yield_from_sequence(true)?;
5834 emit!(self, PseudoInstruction::PopBlock);
5836 emit!(self, Instruction::NotTaken);
5837
5838 self.compile_store(target)?;
5840 } else {
5841 emit!(self, Instruction::GetIter);
5843
5844 self.switch_to_block(for_block);
5845
5846 self.push_fblock(FBlockType::ForLoop, for_block, after_block)?;
5848
5849 emit!(self, Instruction::ForIter { delta: else_block });
5850
5851 self.compile_store(target)?;
5853 };
5854
5855 let was_in_loop = self.ctx.loop_data.replace((for_block, after_block));
5856 self.compile_statements(body)?;
5857 self.ctx.loop_data = was_in_loop;
5858 emit!(self, PseudoInstruction::Jump { delta: for_block });
5859
5860 self.switch_to_block(else_block);
5861
5862 self.pop_fblock(FBlockType::ForLoop);
5865
5866 let saved_range = self.current_source_range;
5868 self.set_source_range(iter.range());
5869 if is_async {
5870 self.emit_end_async_for(end_async_for_target);
5871 } else {
5872 emit!(self, Instruction::EndFor);
5873 emit!(self, Instruction::PopIter);
5874 }
5875 self.set_source_range(saved_range);
5876 self.compile_statements(orelse)?;
5877
5878 self.switch_to_block(after_block);
5879
5880 self.set_source_range(iter.range());
5882
5883 self.leave_conditional_block();
5884 Ok(())
5885 }
5886
5887 fn forbidden_name(&mut self, name: &str, ctx: NameUsage) -> CompileResult<bool> {
5888 if ctx == NameUsage::Store && name == "__debug__" {
5889 return Err(self.error(CodegenErrorType::Assign("__debug__")));
5890 }
5892 if ctx == NameUsage::Delete && name == "__debug__" {
5893 return Err(self.error(CodegenErrorType::Delete("__debug__")));
5894 }
5896 Ok(false)
5897 }
5898
5899 fn compile_error_forbidden_name(&mut self, name: &str) -> CodegenError {
5900 self.error(CodegenErrorType::SyntaxError(format!(
5901 "cannot use forbidden name '{name}' in pattern"
5902 )))
5903 }
5904
5905 fn ensure_fail_pop(&mut self, pc: &mut PatternContext, n: usize) -> CompileResult<()> {
5908 let required_size = n + 1;
5909 if required_size <= pc.fail_pop.len() {
5910 return Ok(());
5911 }
5912 while pc.fail_pop.len() < required_size {
5913 let new_block = self.new_block();
5914 pc.fail_pop.push(new_block);
5915 }
5916 Ok(())
5917 }
5918
5919 fn jump_to_fail_pop(&mut self, pc: &mut PatternContext, op: JumpOp) -> CompileResult<()> {
5920 let pops = pc.on_top + pc.stores.len();
5923 self.ensure_fail_pop(pc, pops)?;
5925 match op {
5927 JumpOp::Jump => {
5928 emit!(
5929 self,
5930 PseudoInstruction::Jump {
5931 delta: pc.fail_pop[pops]
5932 }
5933 );
5934 }
5935 JumpOp::PopJumpIfFalse => {
5936 emit!(
5937 self,
5938 Instruction::PopJumpIfFalse {
5939 delta: pc.fail_pop[pops]
5940 }
5941 );
5942 }
5943 }
5944 Ok(())
5945 }
5946
5947 fn emit_and_reset_fail_pop(&mut self, pc: &mut PatternContext) -> CompileResult<()> {
5950 if pc.fail_pop.is_empty() {
5952 debug_assert!(pc.fail_pop.is_empty());
5953 return Ok(());
5954 }
5955 for &label in pc.fail_pop.iter().skip(1).rev() {
5957 self.switch_to_block(label);
5958 emit!(self, Instruction::PopTop);
5960 }
5961 self.switch_to_block(pc.fail_pop[0]);
5963 pc.fail_pop.clear();
5964 pc.fail_pop.shrink_to_fit();
5966 Ok(())
5967 }
5968
5969 fn pattern_helper_rotate(&mut self, mut count: usize) -> CompileResult<()> {
5971 while count > 1 {
5977 emit!(
5979 self,
5980 Instruction::Swap {
5981 i: u32::try_from(count).unwrap()
5982 }
5983 );
5984 count -= 1;
5985 }
5986 Ok(())
5987 }
5988
5989 fn pattern_helper_store_name(
5996 &mut self,
5997 n: Option<&ast::Identifier>,
5998 pc: &mut PatternContext,
5999 ) -> CompileResult<()> {
6000 match n {
6001 None => {
6003 emit!(self, Instruction::PopTop);
6004 Ok(())
6005 }
6006 Some(name) => {
6007 if self.forbidden_name(name.as_str(), NameUsage::Store)? {
6009 return Err(self.compile_error_forbidden_name(name.as_str()));
6010 }
6011
6012 if pc.stores.contains(&name.to_string()) {
6015 return Err(
6016 self.error(CodegenErrorType::DuplicateStore(name.as_str().to_string()))
6017 );
6018 }
6019
6020 let rotations = pc.on_top + pc.stores.len() + 1;
6022 self.pattern_helper_rotate(rotations)?;
6023
6024 pc.stores.push(name.to_string());
6026 Ok(())
6027 }
6028 }
6029 }
6030
6031 fn pattern_unpack_helper(&mut self, elts: &[ast::Pattern]) -> CompileResult<()> {
6032 let n = elts.len();
6033 let mut seen_star = false;
6034 for (i, elt) in elts.iter().enumerate() {
6035 if elt.is_match_star() {
6036 if !seen_star {
6037 if i >= (1 << 8) || (n - i - 1) >= ((i32::MAX as usize) >> 8) {
6038 todo!();
6039 }
6041 let counts = UnpackExArgs {
6042 before: u8::try_from(i).unwrap(),
6043 after: u8::try_from(n - i - 1).unwrap(),
6044 };
6045 emit!(self, Instruction::UnpackEx { counts });
6046 seen_star = true;
6047 } else {
6048 return Err(self.error(CodegenErrorType::MultipleStarArgs));
6050 }
6052 }
6053 }
6054 if !seen_star {
6055 emit!(
6056 self,
6057 Instruction::UnpackSequence {
6058 count: u32::try_from(n).unwrap()
6059 }
6060 );
6061 }
6062 Ok(())
6063 }
6064
6065 fn pattern_helper_sequence_unpack(
6066 &mut self,
6067 patterns: &[ast::Pattern],
6068 _star: Option<usize>,
6069 pc: &mut PatternContext,
6070 ) -> CompileResult<()> {
6071 self.pattern_unpack_helper(patterns)?;
6073 let size = patterns.len();
6074 pc.on_top += size;
6076 for pattern in patterns {
6078 pc.on_top -= 1;
6080 self.compile_pattern_subpattern(pattern, pc)?;
6081 }
6082 Ok(())
6083 }
6084
6085 fn pattern_helper_sequence_subscr(
6086 &mut self,
6087 patterns: &[ast::Pattern],
6088 star: usize,
6089 pc: &mut PatternContext,
6090 ) -> CompileResult<()> {
6091 pc.on_top += 1;
6093 for (i, pattern) in patterns.iter().enumerate() {
6094 if i == star {
6098 continue;
6101 }
6102 emit!(self, Instruction::Copy { i: 1 });
6104 if i < star {
6105 self.emit_load_const(ConstantData::Integer { value: i.into() });
6107 } else {
6108 emit!(self, Instruction::GetLen);
6111 self.emit_load_const(ConstantData::Integer {
6112 value: (patterns.len() - i).into(),
6113 });
6114 emit!(
6116 self,
6117 Instruction::BinaryOp {
6118 op: BinaryOperator::Subtract
6119 }
6120 );
6121 }
6122 emit!(
6124 self,
6125 Instruction::BinaryOp {
6126 op: BinaryOperator::Subscr
6127 }
6128 );
6129 self.compile_pattern_subpattern(pattern, pc)?;
6131 }
6132 pc.on_top -= 1;
6134 emit!(self, Instruction::PopTop);
6135 Ok(())
6136 }
6137
6138 fn compile_pattern_subpattern(
6139 &mut self,
6140 p: &ast::Pattern,
6141 pc: &mut PatternContext,
6142 ) -> CompileResult<()> {
6143 let old_allow_irrefutable = pc.allow_irrefutable;
6145 pc.allow_irrefutable = true;
6147 self.compile_pattern(p, pc)?;
6149 pc.allow_irrefutable = old_allow_irrefutable;
6151 Ok(())
6152 }
6153
6154 fn compile_pattern_as(
6155 &mut self,
6156 p: &ast::PatternMatchAs,
6157 pc: &mut PatternContext,
6158 ) -> CompileResult<()> {
6159 if p.pattern.is_none() {
6161 if !pc.allow_irrefutable {
6162 if let Some(_name) = p.name.as_ref() {
6163 return Err(self.error(CodegenErrorType::UnreachablePattern(
6166 PatternUnreachableReason::NameCapture,
6167 )));
6168 } else {
6169 return Err(self.error(CodegenErrorType::UnreachablePattern(
6171 PatternUnreachableReason::Wildcard,
6172 )));
6173 }
6174 }
6175 return self.pattern_helper_store_name(p.name.as_ref(), pc);
6177 }
6178
6179 pc.on_top += 1;
6181 emit!(self, Instruction::Copy { i: 1 });
6182 self.compile_pattern(p.pattern.as_ref().unwrap(), pc)?;
6184 pc.on_top -= 1;
6186 self.pattern_helper_store_name(p.name.as_ref(), pc)?;
6188 Ok(())
6189 }
6190
6191 fn compile_pattern_star(
6192 &mut self,
6193 p: &ast::PatternMatchStar,
6194 pc: &mut PatternContext,
6195 ) -> CompileResult<()> {
6196 self.pattern_helper_store_name(p.name.as_ref(), pc)?;
6197 Ok(())
6198 }
6199
6200 fn validate_kwd_attrs(
6203 &mut self,
6204 attrs: &[ast::Identifier],
6205 _patterns: &[ast::Pattern],
6206 ) -> CompileResult<()> {
6207 let n_attrs = attrs.len();
6208 for i in 0..n_attrs {
6209 let attr = attrs[i].as_str();
6210 if self.forbidden_name(attr, NameUsage::Store)? {
6212 return Err(self.compile_error_forbidden_name(attr));
6214 }
6215 for ident in attrs.iter().take(n_attrs).skip(i + 1) {
6217 let other = ident.as_str();
6218 if attr == other {
6219 return Err(self.error(CodegenErrorType::RepeatedAttributePattern));
6220 }
6221 }
6222 }
6223 Ok(())
6224 }
6225
6226 fn compile_pattern_class(
6227 &mut self,
6228 p: &ast::PatternMatchClass,
6229 pc: &mut PatternContext,
6230 ) -> CompileResult<()> {
6231 let match_class = p;
6233 let patterns = &match_class.arguments.patterns;
6234
6235 let mut kwd_attrs = Vec::with_capacity(match_class.arguments.keywords.len());
6238 let mut kwd_patterns = Vec::with_capacity(match_class.arguments.keywords.len());
6239 for kwd in &match_class.arguments.keywords {
6240 kwd_attrs.push(kwd.attr.clone());
6241 kwd_patterns.push(kwd.pattern.clone());
6242 }
6243
6244 let nargs = patterns.len();
6245 let n_attrs = kwd_attrs.len();
6246
6247 if nargs > u32::MAX as usize || (nargs + n_attrs).saturating_sub(1) > i32::MAX as usize {
6249 return Err(self.error(CodegenErrorType::SyntaxError(
6250 "too many sub-patterns in class pattern".to_owned(),
6251 )));
6252 }
6253
6254 if n_attrs != 0 {
6256 self.validate_kwd_attrs(&kwd_attrs, &kwd_patterns)?;
6257 }
6258
6259 self.compile_expression(&match_class.cls)?;
6261
6262 let mut attr_names = vec![];
6264 for name in &kwd_attrs {
6265 attr_names.push(ConstantData::Str {
6267 value: name.as_str().to_string().into(),
6268 });
6269 }
6270
6271 self.emit_load_const(ConstantData::Tuple {
6274 elements: attr_names,
6275 });
6276 emit!(
6278 self,
6279 Instruction::MatchClass {
6280 count: u32::try_from(nargs).unwrap()
6281 }
6282 );
6283 emit!(self, Instruction::Copy { i: 1 });
6285 self.emit_load_const(ConstantData::None);
6287 emit!(
6289 self,
6290 Instruction::IsOp {
6291 invert: Invert::Yes
6292 }
6293 );
6294
6295 pc.on_top += 1;
6297 self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
6298
6299 let total = nargs + n_attrs;
6301 emit!(
6302 self,
6303 Instruction::UnpackSequence {
6304 count: u32::try_from(total).unwrap()
6305 }
6306 );
6307 pc.on_top += total;
6308 pc.on_top -= 1;
6309
6310 for subpattern in patterns.iter().chain(kwd_patterns.iter()) {
6312 let is_true_wildcard = match subpattern {
6314 ast::Pattern::MatchAs(match_as) => {
6315 match_as.pattern.is_none() && match_as.name.is_none()
6317 }
6318 _ => subpattern.is_wildcard(),
6319 };
6320
6321 pc.on_top -= 1;
6323
6324 if is_true_wildcard {
6325 emit!(self, Instruction::PopTop);
6326 continue; }
6328
6329 self.compile_pattern_subpattern(subpattern, pc)?;
6331 }
6332 Ok(())
6333 }
6334
6335 fn compile_pattern_mapping(
6336 &mut self,
6337 p: &ast::PatternMatchMapping,
6338 pc: &mut PatternContext,
6339 ) -> CompileResult<()> {
6340 let mapping = p;
6341 let keys = &mapping.keys;
6342 let patterns = &mapping.patterns;
6343 let size = keys.len();
6344 let star_target = &mapping.rest;
6345
6346 if keys.len() != patterns.len() {
6348 return Err(self.error(CodegenErrorType::SyntaxError(format!(
6349 "keys ({}) / patterns ({}) length mismatch in mapping pattern",
6350 keys.len(),
6351 patterns.len()
6352 ))));
6353 }
6354
6355 if let Some(rest) = star_target
6357 && rest.as_str() == "_"
6358 {
6359 return Err(self.error(CodegenErrorType::SyntaxError("invalid syntax".to_string())));
6360 }
6361
6362 pc.on_top += 1;
6365
6366 emit!(self, Instruction::MatchMapping);
6367 self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
6370 if size == 0 && star_target.is_none() {
6374 pc.on_top -= 1;
6376 emit!(self, Instruction::PopTop);
6377 return Ok(());
6378 }
6379
6380 if size > 0 {
6382 emit!(self, Instruction::GetLen);
6384 self.emit_load_const(ConstantData::Integer { value: size.into() });
6385 emit!(
6387 self,
6388 Instruction::CompareOp {
6389 opname: ComparisonOperator::GreaterOrEqual
6390 }
6391 );
6392 self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
6393 }
6395
6396 if size > (i32::MAX as usize + 1) {
6398 return Err(self.error(CodegenErrorType::SyntaxError(
6399 "too many sub-patterns in mapping pattern".to_string(),
6400 )));
6401 }
6402 #[allow(clippy::cast_possible_truncation, reason = "checked right before")]
6403 let size = size as u32;
6404
6405 if size > 0 {
6407 let mut seen = IndexSet::default();
6409 for key in keys {
6410 let is_attribute = matches!(key, ast::Expr::Attribute(_));
6411 let is_literal = matches!(
6412 key,
6413 ast::Expr::NumberLiteral(_)
6414 | ast::Expr::StringLiteral(_)
6415 | ast::Expr::BytesLiteral(_)
6416 | ast::Expr::BooleanLiteral(_)
6417 | ast::Expr::NoneLiteral(_)
6418 );
6419 let key_repr = if is_literal {
6420 UnparseExpr::new(key, &self.source_file).to_string()
6421 } else if is_attribute {
6422 String::new()
6423 } else {
6424 return Err(self.error(CodegenErrorType::SyntaxError(
6425 "mapping pattern keys may only match literals and attribute lookups"
6426 .to_string(),
6427 )));
6428 };
6429
6430 if !key_repr.is_empty() && seen.contains(&key_repr) {
6431 return Err(self.error(CodegenErrorType::SyntaxError(format!(
6432 "mapping pattern checks duplicate key ({key_repr})"
6433 ))));
6434 }
6435 if !key_repr.is_empty() {
6436 seen.insert(key_repr);
6437 }
6438
6439 self.compile_expression(key)?;
6440 }
6441 }
6442 emit!(self, Instruction::BuildTuple { count: size });
6446 emit!(self, Instruction::MatchKeys);
6450 pc.on_top += 2; emit!(self, Instruction::Copy { i: 1 });
6455 self.emit_load_const(ConstantData::None);
6459 emit!(
6460 self,
6461 Instruction::IsOp {
6462 invert: Invert::Yes
6463 }
6464 );
6465
6466 self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
6468 emit!(self, Instruction::UnpackSequence { count: size });
6472 pc.on_top += size as usize; pc.on_top -= 1;
6475
6476 for i in 0..size {
6478 pc.on_top -= 1;
6479 self.compile_pattern_subpattern(&patterns[i as usize], pc)?;
6480 }
6481
6482 pc.on_top -= 2;
6486
6487 if let Some(rest_name) = star_target {
6489 emit!(self, Instruction::BuildMap { count: 0 });
6494 emit!(self, Instruction::Swap { i: 3 });
6496 emit!(self, Instruction::DictUpdate { i: 2 });
6498 emit!(self, Instruction::UnpackSequence { count: size });
6503 let mut remaining = size;
6508 while remaining > 0 {
6509 emit!(self, Instruction::Copy { i: 1 + remaining });
6511 emit!(self, Instruction::Swap { i: 2 });
6513 emit!(self, Instruction::DeleteSubscr);
6515 remaining -= 1;
6517 }
6518 self.pattern_helper_store_name(Some(rest_name), pc)?;
6523
6524 pc.on_top = 0;
6527 } else {
6528 emit!(self, Instruction::PopTop); emit!(self, Instruction::PopTop); }
6534
6535 Ok(())
6536 }
6537
6538 fn compile_pattern_or(
6539 &mut self,
6540 p: &ast::PatternMatchOr,
6541 pc: &mut PatternContext,
6542 ) -> CompileResult<()> {
6543 let end = self.new_block(); let size = p.patterns.len();
6546 if size <= 1 {
6547 return Err(self.error(CodegenErrorType::SyntaxError(
6548 "MatchOr requires at least 2 patterns".to_owned(),
6549 )));
6550 }
6551
6552 let old_pc = pc.clone();
6554 pc.stores = pc.stores.clone();
6556 let mut control: Option<Vec<String>> = None; for (i, alt) in p.patterns.iter().enumerate() {
6560 pc.stores = Vec::new();
6562 pc.allow_irrefutable = (i == size - 1) && old_pc.allow_irrefutable;
6564 pc.fail_pop.clear();
6566 pc.on_top = 0;
6567 emit!(self, Instruction::Copy { i: 1 });
6569 self.compile_pattern(alt, pc)?;
6570
6571 let n_stores = pc.stores.len();
6572 if i == 0 {
6573 control = Some(pc.stores.clone());
6575 } else {
6576 let control_vec = control.as_ref().unwrap();
6577 if n_stores != control_vec.len() {
6578 return Err(self.error(CodegenErrorType::ConflictingNameBindPattern));
6579 } else if n_stores > 0 {
6580 for i_control in (0..n_stores).rev() {
6582 let name = &control_vec[i_control];
6583 let i_stores =
6585 pc.stores.iter().position(|n| n == name).ok_or_else(|| {
6586 self.error(CodegenErrorType::ConflictingNameBindPattern)
6587 })?;
6588 if i_control != i_stores {
6589 assert!(i_stores < i_control, "expected i_stores < i_control");
6591 let rotations = i_stores + 1;
6592 let rotated = pc.stores[0..rotations].to_vec();
6594 for _ in 0..rotations {
6596 pc.stores.remove(0);
6597 }
6598 let insert_pos = i_control - i_stores;
6600 for (j, elem) in rotated.into_iter().enumerate() {
6601 pc.stores.insert(insert_pos + j, elem);
6602 }
6603 for _ in 0..=i_stores {
6605 self.pattern_helper_rotate(i_control + 1)?;
6606 }
6607 }
6608 }
6609 }
6610 }
6611 emit!(self, PseudoInstruction::Jump { delta: end });
6613 self.emit_and_reset_fail_pop(pc)?;
6614 }
6615
6616 *pc = old_pc.clone();
6618 pc.stores = pc.stores.clone();
6620 emit!(self, Instruction::PopTop);
6625 self.jump_to_fail_pop(pc, JumpOp::Jump)?;
6626
6627 self.switch_to_block(end);
6629
6630 let n_stores = control.as_ref().unwrap().len();
6632 let n_rots = n_stores + 1 + pc.on_top + pc.stores.len();
6633 for i in 0..n_stores {
6634 self.pattern_helper_rotate(n_rots)?;
6636 let name = &control.as_ref().unwrap()[i];
6637 if pc.stores.contains(name) {
6639 return Err(self.error(CodegenErrorType::DuplicateStore(name.to_string())));
6640 }
6641 pc.stores.push(name.clone());
6642 }
6643
6644 emit!(self, Instruction::PopTop);
6647 Ok(())
6648 }
6649
6650 fn compile_pattern_sequence(
6651 &mut self,
6652 p: &ast::PatternMatchSequence,
6653 pc: &mut PatternContext,
6654 ) -> CompileResult<()> {
6655 let patterns = &p.patterns; let size = patterns.len();
6658 let mut star: Option<usize> = None;
6659 let mut only_wildcard = true;
6660 let mut star_wildcard = false;
6661
6662 for (i, pattern) in patterns.iter().enumerate() {
6664 if pattern.is_match_star() {
6665 if star.is_some() {
6666 return Err(self.error(CodegenErrorType::MultipleStarArgs));
6668 }
6669 star_wildcard = pattern
6671 .as_match_star()
6672 .map(|m| m.name.is_none())
6673 .unwrap_or(false);
6674 only_wildcard &= star_wildcard;
6675 star = Some(i);
6676 continue;
6677 }
6678 only_wildcard &= pattern
6680 .as_match_as()
6681 .map(|m| m.name.is_none())
6682 .unwrap_or(false);
6683 }
6684
6685 pc.on_top += 1;
6687 emit!(self, Instruction::MatchSequence);
6688 self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
6689
6690 if star.is_none() {
6691 emit!(self, Instruction::GetLen);
6693 self.emit_load_const(ConstantData::Integer { value: size.into() });
6694 emit!(
6695 self,
6696 Instruction::CompareOp {
6697 opname: ComparisonOperator::Equal
6698 }
6699 );
6700 self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
6701 } else if size > 1 {
6702 emit!(self, Instruction::GetLen);
6704 self.emit_load_const(ConstantData::Integer {
6705 value: (size - 1).into(),
6706 });
6707 emit!(
6708 self,
6709 Instruction::CompareOp {
6710 opname: ComparisonOperator::GreaterOrEqual
6711 }
6712 );
6713 self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
6714 }
6715
6716 pc.on_top -= 1;
6718 if only_wildcard {
6719 emit!(self, Instruction::PopTop);
6721 } else if star_wildcard {
6722 self.pattern_helper_sequence_subscr(patterns, star.unwrap(), pc)?;
6723 } else {
6724 self.pattern_helper_sequence_unpack(patterns, star, pc)?;
6725 }
6726 Ok(())
6727 }
6728
6729 fn compile_pattern_value(
6730 &mut self,
6731 p: &ast::PatternMatchValue,
6732 pc: &mut PatternContext,
6733 ) -> CompileResult<()> {
6734 self.compile_expression(&p.value)?;
6736 emit!(
6737 self,
6738 Instruction::CompareOp {
6739 opname: bytecode::ComparisonOperator::Equal
6740 }
6741 );
6742 self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
6744 Ok(())
6745 }
6746
6747 fn compile_pattern_singleton(
6748 &mut self,
6749 p: &ast::PatternMatchSingleton,
6750 pc: &mut PatternContext,
6751 ) -> CompileResult<()> {
6752 self.emit_load_const(match p.value {
6754 ast::Singleton::None => ConstantData::None,
6755 ast::Singleton::False => ConstantData::Boolean { value: false },
6756 ast::Singleton::True => ConstantData::Boolean { value: true },
6757 });
6758 emit!(self, Instruction::IsOp { invert: Invert::No });
6760 self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
6762 Ok(())
6763 }
6764
6765 fn compile_pattern(
6766 &mut self,
6767 pattern_type: &ast::Pattern,
6768 pattern_context: &mut PatternContext,
6769 ) -> CompileResult<()> {
6770 match &pattern_type {
6771 ast::Pattern::MatchValue(pattern_type) => {
6772 self.compile_pattern_value(pattern_type, pattern_context)
6773 }
6774 ast::Pattern::MatchSingleton(pattern_type) => {
6775 self.compile_pattern_singleton(pattern_type, pattern_context)
6776 }
6777 ast::Pattern::MatchSequence(pattern_type) => {
6778 self.compile_pattern_sequence(pattern_type, pattern_context)
6779 }
6780 ast::Pattern::MatchMapping(pattern_type) => {
6781 self.compile_pattern_mapping(pattern_type, pattern_context)
6782 }
6783 ast::Pattern::MatchClass(pattern_type) => {
6784 self.compile_pattern_class(pattern_type, pattern_context)
6785 }
6786 ast::Pattern::MatchStar(pattern_type) => {
6787 self.compile_pattern_star(pattern_type, pattern_context)
6788 }
6789 ast::Pattern::MatchAs(pattern_type) => {
6790 self.compile_pattern_as(pattern_type, pattern_context)
6791 }
6792 ast::Pattern::MatchOr(pattern_type) => {
6793 self.compile_pattern_or(pattern_type, pattern_context)
6794 }
6795 }
6796 }
6797
6798 fn compile_match_inner(
6799 &mut self,
6800 subject: &ast::Expr,
6801 cases: &[ast::MatchCase],
6802 pattern_context: &mut PatternContext,
6803 ) -> CompileResult<()> {
6804 self.compile_expression(subject)?;
6805 let end = self.new_block();
6806
6807 let num_cases = cases.len();
6808 assert!(num_cases > 0);
6809 let has_default = cases.iter().last().unwrap().pattern.is_match_star() && num_cases > 1;
6810
6811 let case_count = num_cases - if has_default { 1 } else { 0 };
6812 for (i, m) in cases.iter().enumerate().take(case_count) {
6813 if i != case_count - 1 {
6815 emit!(self, Instruction::Copy { i: 1 });
6816 }
6817
6818 pattern_context.stores = Vec::with_capacity(1);
6819 pattern_context.allow_irrefutable = m.guard.is_some() || i == case_count - 1;
6820 pattern_context.fail_pop.clear();
6821 pattern_context.on_top = 0;
6822
6823 self.compile_pattern(&m.pattern, pattern_context)?;
6824 assert_eq!(pattern_context.on_top, 0);
6825
6826 for name in &pattern_context.stores {
6827 self.compile_name(name, NameUsage::Store)?;
6828 }
6829
6830 if let Some(ref guard) = m.guard {
6831 self.ensure_fail_pop(pattern_context, 0)?;
6832 self.compile_expression(guard)?;
6834 emit!(self, Instruction::ToBool);
6835 emit!(
6836 self,
6837 Instruction::PopJumpIfFalse {
6838 delta: pattern_context.fail_pop[0]
6839 }
6840 );
6841 }
6842
6843 if i != case_count - 1 {
6844 emit!(self, Instruction::PopTop);
6845 }
6846
6847 self.compile_statements(&m.body)?;
6848 emit!(self, PseudoInstruction::Jump { delta: end });
6849 self.emit_and_reset_fail_pop(pattern_context)?;
6850 }
6851
6852 if has_default {
6853 let m = &cases[num_cases - 1];
6854 if num_cases == 1 {
6855 emit!(self, Instruction::PopTop);
6856 } else {
6857 emit!(self, Instruction::Nop);
6858 }
6859 if let Some(ref guard) = m.guard {
6860 self.compile_expression(guard)?;
6862 emit!(self, Instruction::Copy { i: 1 });
6863 emit!(self, Instruction::PopJumpIfFalse { delta: end });
6864 emit!(self, Instruction::PopTop);
6865 }
6866 self.compile_statements(&m.body)?;
6867 }
6868 self.switch_to_block(end);
6869 Ok(())
6870 }
6871
6872 fn compile_match(
6873 &mut self,
6874 subject: &ast::Expr,
6875 cases: &[ast::MatchCase],
6876 ) -> CompileResult<()> {
6877 self.enter_conditional_block();
6878 let mut pattern_context = PatternContext::new();
6879 self.compile_match_inner(subject, cases, &mut pattern_context)?;
6880 self.leave_conditional_block();
6881 Ok(())
6882 }
6883
6884 fn compile_addcompare(&mut self, op: &ast::CmpOp) {
6886 use bytecode::ComparisonOperator::*;
6887 match op {
6888 ast::CmpOp::Eq => emit!(self, Instruction::CompareOp { opname: Equal }),
6889 ast::CmpOp::NotEq => emit!(self, Instruction::CompareOp { opname: NotEqual }),
6890 ast::CmpOp::Lt => emit!(self, Instruction::CompareOp { opname: Less }),
6891 ast::CmpOp::LtE => emit!(
6892 self,
6893 Instruction::CompareOp {
6894 opname: LessOrEqual
6895 }
6896 ),
6897 ast::CmpOp::Gt => emit!(self, Instruction::CompareOp { opname: Greater }),
6898 ast::CmpOp::GtE => {
6899 emit!(
6900 self,
6901 Instruction::CompareOp {
6902 opname: GreaterOrEqual
6903 }
6904 )
6905 }
6906 ast::CmpOp::In => emit!(self, Instruction::ContainsOp { invert: Invert::No }),
6907 ast::CmpOp::NotIn => emit!(
6908 self,
6909 Instruction::ContainsOp {
6910 invert: Invert::Yes
6911 }
6912 ),
6913 ast::CmpOp::Is => emit!(self, Instruction::IsOp { invert: Invert::No }),
6914 ast::CmpOp::IsNot => emit!(
6915 self,
6916 Instruction::IsOp {
6917 invert: Invert::Yes
6918 }
6919 ),
6920 }
6921 }
6922
6923 fn compile_compare(
6942 &mut self,
6943 left: &ast::Expr,
6944 ops: &[ast::CmpOp],
6945 comparators: &[ast::Expr],
6946 ) -> CompileResult<()> {
6947 let compare_range = self.current_source_range;
6949 let (last_op, mid_ops) = ops.split_last().unwrap();
6950 let (last_comparator, mid_comparators) = comparators.split_last().unwrap();
6951
6952 self.compile_expression(left)?;
6954
6955 if mid_comparators.is_empty() {
6956 self.compile_expression(last_comparator)?;
6957 self.set_source_range(compare_range);
6958 self.compile_addcompare(last_op);
6959
6960 return Ok(());
6961 }
6962
6963 let cleanup = self.new_block();
6964
6965 for (op, comparator) in mid_ops.iter().zip(mid_comparators) {
6967 self.compile_expression(comparator)?;
6968
6969 self.set_source_range(compare_range);
6971 emit!(self, Instruction::Swap { i: 2 });
6972 emit!(self, Instruction::Copy { i: 2 });
6973
6974 self.compile_addcompare(op);
6975
6976 emit!(self, Instruction::Copy { i: 1 });
6978 emit!(self, Instruction::PopJumpIfFalse { delta: cleanup });
6979 emit!(self, Instruction::PopTop);
6980 }
6981
6982 self.compile_expression(last_comparator)?;
6983 self.set_source_range(compare_range);
6984 self.compile_addcompare(last_op);
6985
6986 let end = self.new_block();
6987 emit!(self, PseudoInstruction::Jump { delta: end });
6988
6989 self.switch_to_block(cleanup);
6991 emit!(self, Instruction::Swap { i: 2 });
6992 emit!(self, Instruction::PopTop);
6993
6994 self.switch_to_block(end);
6995 Ok(())
6996 }
6997
6998 fn compile_jump_if_compare(
6999 &mut self,
7000 left: &ast::Expr,
7001 ops: &[ast::CmpOp],
7002 comparators: &[ast::Expr],
7003 condition: bool,
7004 target_block: BlockIdx,
7005 ) -> CompileResult<()> {
7006 let compare_range = self.current_source_range;
7007 let (last_op, mid_ops) = ops.split_last().unwrap();
7008 let (last_comparator, mid_comparators) = comparators.split_last().unwrap();
7009
7010 self.compile_expression(left)?;
7011
7012 if mid_comparators.is_empty() {
7013 self.compile_expression(last_comparator)?;
7014 self.set_source_range(compare_range);
7015 self.compile_addcompare(last_op);
7016 self.emit_pop_jump_by_condition(condition, target_block);
7017 return Ok(());
7018 }
7019
7020 let cleanup = self.new_block();
7021 let end = self.new_block();
7022
7023 for (op, comparator) in mid_ops.iter().zip(mid_comparators) {
7024 self.compile_expression(comparator)?;
7025 self.set_source_range(compare_range);
7026 emit!(self, Instruction::Swap { i: 2 });
7027 emit!(self, Instruction::Copy { i: 2 });
7028 self.compile_addcompare(op);
7029 emit!(self, Instruction::PopJumpIfFalse { delta: cleanup });
7030 }
7031
7032 self.compile_expression(last_comparator)?;
7033 self.set_source_range(compare_range);
7034 self.compile_addcompare(last_op);
7035 self.emit_pop_jump_by_condition(condition, target_block);
7036 emit!(self, PseudoInstruction::Jump { delta: end });
7037
7038 self.switch_to_block(cleanup);
7039 emit!(self, Instruction::PopTop);
7040 if !condition {
7041 emit!(
7042 self,
7043 PseudoInstruction::Jump {
7044 delta: target_block
7045 }
7046 );
7047 }
7048
7049 self.switch_to_block(end);
7050 Ok(())
7051 }
7052
7053 fn emit_pop_jump_by_condition(&mut self, condition: bool, target_block: BlockIdx) {
7054 if condition {
7055 emit!(
7056 self,
7057 Instruction::PopJumpIfTrue {
7058 delta: target_block
7059 }
7060 );
7061 } else {
7062 emit!(
7063 self,
7064 Instruction::PopJumpIfFalse {
7065 delta: target_block,
7066 }
7067 );
7068 }
7069 }
7070
7071 fn compile_annotation(&mut self, annotation: &ast::Expr) -> CompileResult<()> {
7072 if self.future_annotations {
7073 self.emit_load_const(ConstantData::Str {
7074 value: UnparseExpr::new(annotation, &self.source_file)
7075 .to_string()
7076 .into(),
7077 });
7078 } else {
7079 let was_in_annotation = self.in_annotation;
7080 self.in_annotation = true;
7081
7082 let result = match annotation {
7084 ast::Expr::Starred(ast::ExprStarred { value, .. }) => {
7085 self.compile_expression(value)?;
7088 emit!(self, Instruction::UnpackSequence { count: 1 });
7089 Ok(())
7090 }
7091 _ => self.compile_expression(annotation),
7092 };
7093
7094 self.in_annotation = was_in_annotation;
7095 result?;
7096 }
7097 Ok(())
7098 }
7099
7100 fn compile_annotated_assign(
7101 &mut self,
7102 target: &ast::Expr,
7103 annotation: &ast::Expr,
7104 value: Option<&ast::Expr>,
7105 simple: bool,
7106 ) -> CompileResult<()> {
7107 if let Some(value) = value {
7109 self.compile_expression(value)?;
7110 self.compile_store(target)?;
7111 }
7112
7113 if simple
7115 && !self.ctx.in_func()
7116 && let ast::Expr::Name(ast::ExprName { id, .. }) = target
7117 {
7118 if self.future_annotations {
7119 self.compile_annotation(annotation)?;
7122 let annotations_name = self.name("__annotations__");
7124 emit!(
7125 self,
7126 Instruction::LoadName {
7127 namei: annotations_name
7128 }
7129 );
7130 self.emit_load_const(ConstantData::Str {
7132 value: self.mangle(id.as_str()).into_owned().into(),
7133 });
7134 emit!(self, Instruction::StoreSubscr);
7136 } else {
7137 if self.current_symbol_table().has_conditional_annotations {
7139 let code_info = self.current_code_info();
7142 let annotation_index = code_info.next_conditional_annotation_index;
7143 code_info.next_conditional_annotation_index += 1;
7144
7145 let scope_type = self.current_symbol_table().typ;
7148 let in_conditional_block = self.current_code_info().in_conditional_block > 0;
7149 let is_conditional =
7150 matches!(scope_type, CompilerScope::Module | CompilerScope::Class)
7151 || in_conditional_block;
7152
7153 if is_conditional {
7155 self.load_name("__conditional_annotations__")?;
7156 self.emit_load_const(ConstantData::Integer {
7157 value: annotation_index.into(),
7158 });
7159 emit!(self, Instruction::SetAdd { i: 1 });
7160 emit!(self, Instruction::PopTop);
7161 }
7162 }
7163 }
7164 }
7165
7166 Ok(())
7167 }
7168
7169 fn compile_store(&mut self, target: &ast::Expr) -> CompileResult<()> {
7170 match &target {
7171 ast::Expr::Name(ast::ExprName { id, .. }) => self.store_name(id.as_str())?,
7172 ast::Expr::Subscript(ast::ExprSubscript {
7173 value, slice, ctx, ..
7174 }) => {
7175 self.compile_subscript(value, slice, *ctx)?;
7176 }
7177 ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) => {
7178 self.compile_expression(value)?;
7179 let namei = self.name(attr.as_str());
7180 emit!(self, Instruction::StoreAttr { namei });
7181 }
7182 ast::Expr::List(ast::ExprList { elts, .. })
7183 | ast::Expr::Tuple(ast::ExprTuple { elts, .. }) => {
7184 let mut seen_star = false;
7185
7186 for (i, element) in elts.iter().enumerate() {
7188 if let ast::Expr::Starred(_) = &element {
7189 if seen_star {
7190 return Err(self.error(CodegenErrorType::MultipleStarArgs));
7191 } else {
7192 seen_star = true;
7193 let before = i;
7194 let after = elts.len() - i - 1;
7195 let (before, after) = (|| Some((before.to_u8()?, after.to_u8()?)))()
7196 .ok_or_else(|| {
7197 self.error_ranged(
7198 CodegenErrorType::TooManyStarUnpack,
7199 target.range(),
7200 )
7201 })?;
7202 let counts = bytecode::UnpackExArgs { before, after };
7203 emit!(self, Instruction::UnpackEx { counts });
7204 }
7205 }
7206 }
7207
7208 if !seen_star {
7209 emit!(
7210 self,
7211 Instruction::UnpackSequence {
7212 count: elts.len().to_u32(),
7213 }
7214 );
7215 }
7216
7217 for element in elts {
7218 if let ast::Expr::Starred(ast::ExprStarred { value, .. }) = &element {
7219 self.compile_store(value)?;
7220 } else {
7221 self.compile_store(element)?;
7222 }
7223 }
7224 }
7225 _ => {
7226 return Err(self.error(match target {
7227 ast::Expr::Starred(_) => CodegenErrorType::SyntaxError(
7228 "starred assignment target must be in a list or tuple".to_owned(),
7229 ),
7230 _ => CodegenErrorType::Assign(target.python_name()),
7231 }));
7232 }
7233 }
7234
7235 Ok(())
7236 }
7237
7238 fn compile_augassign(
7239 &mut self,
7240 target: &ast::Expr,
7241 op: &ast::Operator,
7242 value: &ast::Expr,
7243 ) -> CompileResult<()> {
7244 enum AugAssignKind<'a> {
7245 Name { id: &'a str },
7246 Subscript,
7247 Attr { idx: bytecode::NameIdx },
7248 }
7249
7250 let kind = match &target {
7251 ast::Expr::Name(ast::ExprName { id, .. }) => {
7252 let id = id.as_str();
7253 self.compile_name(id, NameUsage::Load)?;
7254 AugAssignKind::Name { id }
7255 }
7256 ast::Expr::Subscript(ast::ExprSubscript {
7257 value,
7258 slice,
7259 ctx: _,
7260 ..
7261 }) => {
7262 self.compile_expression(value)?;
7265 self.compile_expression(slice)?;
7266 emit!(self, Instruction::Copy { i: 2 });
7267 emit!(self, Instruction::Copy { i: 2 });
7268 emit!(
7269 self,
7270 Instruction::BinaryOp {
7271 op: BinaryOperator::Subscr
7272 }
7273 );
7274 AugAssignKind::Subscript
7275 }
7276 ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) => {
7277 let attr = attr.as_str();
7278 self.compile_expression(value)?;
7279 emit!(self, Instruction::Copy { i: 1 });
7280 let idx = self.name(attr);
7281 self.emit_load_attr(idx);
7282 AugAssignKind::Attr { idx }
7283 }
7284 _ => {
7285 return Err(self.error(CodegenErrorType::Assign(target.python_name())));
7286 }
7287 };
7288
7289 self.compile_expression(value)?;
7290 self.compile_op(op, true);
7291
7292 match kind {
7293 AugAssignKind::Name { id } => {
7294 self.compile_name(id, NameUsage::Store)?;
7296 }
7297 AugAssignKind::Subscript => {
7298 emit!(self, Instruction::Swap { i: 3 });
7300 emit!(self, Instruction::Swap { i: 2 });
7301 emit!(self, Instruction::StoreSubscr);
7302 }
7303 AugAssignKind::Attr { idx } => {
7304 emit!(self, Instruction::Swap { i: 2 });
7306 emit!(self, Instruction::StoreAttr { namei: idx });
7307 }
7308 }
7309
7310 Ok(())
7311 }
7312
7313 fn compile_op(&mut self, op: &ast::Operator, inplace: bool) {
7314 let bin_op = match op {
7315 ast::Operator::Add => BinaryOperator::Add,
7316 ast::Operator::Sub => BinaryOperator::Subtract,
7317 ast::Operator::Mult => BinaryOperator::Multiply,
7318 ast::Operator::MatMult => BinaryOperator::MatrixMultiply,
7319 ast::Operator::Div => BinaryOperator::TrueDivide,
7320 ast::Operator::FloorDiv => BinaryOperator::FloorDivide,
7321 ast::Operator::Mod => BinaryOperator::Remainder,
7322 ast::Operator::Pow => BinaryOperator::Power,
7323 ast::Operator::LShift => BinaryOperator::Lshift,
7324 ast::Operator::RShift => BinaryOperator::Rshift,
7325 ast::Operator::BitOr => BinaryOperator::Or,
7326 ast::Operator::BitXor => BinaryOperator::Xor,
7327 ast::Operator::BitAnd => BinaryOperator::And,
7328 };
7329
7330 let op = if inplace { bin_op.as_inplace() } else { bin_op };
7331 emit!(self, Instruction::BinaryOp { op })
7332 }
7333
7334 fn compile_jump_if(
7343 &mut self,
7344 expression: &ast::Expr,
7345 condition: bool,
7346 target_block: BlockIdx,
7347 ) -> CompileResult<()> {
7348 let prev_source_range = self.current_source_range;
7349 self.set_source_range(expression.range());
7350
7351 let result = match &expression {
7353 ast::Expr::BoolOp(ast::ExprBoolOp { op, values, .. }) => {
7354 match op {
7355 ast::BoolOp::And => {
7356 if condition {
7357 let end_block = self.new_block();
7359 let (last_value, values) = values.split_last().unwrap();
7360
7361 for value in values {
7363 self.compile_jump_if(value, false, end_block)?;
7364 }
7365
7366 self.compile_jump_if(last_value, true, target_block)?;
7368 self.switch_to_block(end_block);
7369 } else {
7370 for value in values {
7372 self.compile_jump_if(value, false, target_block)?;
7373 }
7374 }
7375 }
7376 ast::BoolOp::Or => {
7377 if condition {
7378 for value in values {
7380 self.compile_jump_if(value, true, target_block)?;
7381 }
7382 } else {
7383 let end_block = self.new_block();
7385 let (last_value, values) = values.split_last().unwrap();
7386
7387 for value in values {
7389 self.compile_jump_if(value, true, end_block)?;
7390 }
7391
7392 self.compile_jump_if(last_value, false, target_block)?;
7394 self.switch_to_block(end_block);
7395 }
7396 }
7397 }
7398 Ok(())
7399 }
7400 ast::Expr::UnaryOp(ast::ExprUnaryOp {
7401 op: ast::UnaryOp::Not,
7402 operand,
7403 ..
7404 }) => self.compile_jump_if(operand, !condition, target_block),
7405 ast::Expr::Compare(ast::ExprCompare {
7406 left,
7407 ops,
7408 comparators,
7409 ..
7410 }) if ops.len() > 1 => {
7411 self.compile_jump_if_compare(left, ops, comparators, condition, target_block)
7412 }
7413 ast::Expr::Compare(ast::ExprCompare {
7415 left,
7416 ops,
7417 comparators,
7418 ..
7419 }) if ops.len() == 1
7420 && matches!(ops[0], ast::CmpOp::Is | ast::CmpOp::IsNot)
7421 && comparators.len() == 1
7422 && matches!(&comparators[0], ast::Expr::NoneLiteral(_)) =>
7423 {
7424 self.compile_expression(left)?;
7425 let is_not = matches!(ops[0], ast::CmpOp::IsNot);
7426 let jump_if_none = condition != is_not;
7431 if jump_if_none {
7432 emit!(
7433 self,
7434 Instruction::PopJumpIfNone {
7435 delta: target_block,
7436 }
7437 );
7438 } else {
7439 emit!(
7440 self,
7441 Instruction::PopJumpIfNotNone {
7442 delta: target_block,
7443 }
7444 );
7445 }
7446 Ok(())
7447 }
7448 _ => {
7449 self.compile_expression(expression)?;
7451 if !matches!(expression, ast::Expr::Compare(_)) {
7453 emit!(self, Instruction::ToBool);
7454 }
7455 if condition {
7456 emit!(
7457 self,
7458 Instruction::PopJumpIfTrue {
7459 delta: target_block,
7460 }
7461 );
7462 } else {
7463 emit!(
7464 self,
7465 Instruction::PopJumpIfFalse {
7466 delta: target_block,
7467 }
7468 );
7469 }
7470 Ok(())
7471 }
7472 };
7473
7474 self.set_source_range(prev_source_range);
7475 result
7476 }
7477
7478 fn compile_bool_op(&mut self, op: &ast::BoolOp, values: &[ast::Expr]) -> CompileResult<()> {
7481 self.compile_bool_op_with_target(op, values, None)
7482 }
7483
7484 fn compile_bool_op_with_target(
7489 &mut self,
7490 op: &ast::BoolOp,
7491 values: &[ast::Expr],
7492 short_circuit_target: Option<BlockIdx>,
7493 ) -> CompileResult<()> {
7494 let after_block = self.new_block();
7495 let (last_value, values) = values.split_last().unwrap();
7496 let jump_target = short_circuit_target.unwrap_or(after_block);
7497
7498 for value in values {
7499 if short_circuit_target.is_none()
7503 && let ast::Expr::BoolOp(ast::ExprBoolOp {
7504 op: inner_op,
7505 values: inner_values,
7506 ..
7507 }) = value
7508 && inner_op != op
7509 {
7510 let pop_block = self.new_block();
7511 self.compile_bool_op_with_target(inner_op, inner_values, Some(pop_block))?;
7512 self.emit_short_circuit_test(op, after_block);
7513 self.switch_to_block(pop_block);
7514 emit!(self, Instruction::PopTop);
7515 continue;
7516 }
7517
7518 self.compile_expression(value)?;
7519 self.emit_short_circuit_test(op, jump_target);
7520 emit!(self, Instruction::PopTop);
7521 }
7522
7523 self.compile_expression(last_value)?;
7525 self.switch_to_block(after_block);
7526 Ok(())
7527 }
7528
7529 fn emit_short_circuit_test(&mut self, op: &ast::BoolOp, target: BlockIdx) {
7532 emit!(self, Instruction::Copy { i: 1 });
7533 emit!(self, Instruction::ToBool);
7534 match op {
7535 ast::BoolOp::And => {
7536 emit!(self, Instruction::PopJumpIfFalse { delta: target });
7537 }
7538 ast::BoolOp::Or => {
7539 emit!(self, Instruction::PopJumpIfTrue { delta: target });
7540 }
7541 }
7542 }
7543
7544 fn compile_dict(&mut self, items: &[ast::DictItem]) -> CompileResult<()> {
7545 let has_unpacking = items.iter().any(|item| item.key.is_none());
7546
7547 if !has_unpacking {
7548 const STACK_LIMIT: usize = 15;
7553 const BIG_MAP_CHUNK: usize = 17;
7554
7555 if items.len() <= STACK_LIMIT {
7556 for item in items {
7557 self.compile_expression(item.key.as_ref().unwrap())?;
7558 self.compile_expression(&item.value)?;
7559 }
7560 emit!(
7561 self,
7562 Instruction::BuildMap {
7563 count: u32::try_from(items.len()).expect("too many dict items"),
7564 }
7565 );
7566 } else {
7567 let n = items.len();
7570 let remainder = n % BIG_MAP_CHUNK;
7571 let n_big_chunks = n / BIG_MAP_CHUNK;
7572 let (big_count, tail_count) = if remainder > 0 && remainder <= STACK_LIMIT {
7575 (n_big_chunks, remainder)
7576 } else {
7577 let total_map_add = if remainder == 0 {
7579 n_big_chunks
7580 } else {
7581 n_big_chunks + 1
7582 };
7583 (total_map_add, 0usize)
7584 };
7585
7586 emit!(self, Instruction::BuildMap { count: 0 });
7587
7588 let mut idx = 0;
7589 for chunk_i in 0..big_count {
7590 if chunk_i > 0 {
7591 emit!(self, Instruction::BuildMap { count: 0 });
7592 }
7593 let chunk_size = if idx + BIG_MAP_CHUNK <= n - tail_count {
7594 BIG_MAP_CHUNK
7595 } else {
7596 n - tail_count - idx
7597 };
7598 for item in &items[idx..idx + chunk_size] {
7599 self.compile_expression(item.key.as_ref().unwrap())?;
7600 self.compile_expression(&item.value)?;
7601 emit!(self, Instruction::MapAdd { i: 1 });
7602 }
7603 if chunk_i > 0 {
7604 emit!(self, Instruction::DictUpdate { i: 1 });
7605 }
7606 idx += chunk_size;
7607 }
7608
7609 if tail_count > 0 {
7611 for item in &items[idx..idx + tail_count] {
7612 self.compile_expression(item.key.as_ref().unwrap())?;
7613 self.compile_expression(&item.value)?;
7614 }
7615 emit!(
7616 self,
7617 Instruction::BuildMap {
7618 count: tail_count.to_u32(),
7619 }
7620 );
7621 emit!(self, Instruction::DictUpdate { i: 1 });
7622 }
7623 }
7624 return Ok(());
7625 }
7626
7627 let mut have_dict = false;
7631 let mut elements: u32 = 0;
7632
7633 macro_rules! flush_pending {
7636 () => {
7637 #[allow(unused_assignments)]
7638 if elements > 0 {
7639 emit!(self, Instruction::BuildMap { count: elements });
7640 if have_dict {
7641 emit!(self, Instruction::DictUpdate { i: 1 });
7642 } else {
7643 have_dict = true;
7644 }
7645 elements = 0;
7646 }
7647 };
7648 }
7649
7650 for item in items {
7651 if let Some(key) = &item.key {
7652 self.compile_expression(key)?;
7654 self.compile_expression(&item.value)?;
7655 elements += 1;
7656 } else {
7657 flush_pending!();
7659 if !have_dict {
7660 emit!(self, Instruction::BuildMap { count: 0 });
7661 have_dict = true;
7662 }
7663 self.compile_expression(&item.value)?;
7664 emit!(self, Instruction::DictUpdate { i: 1 });
7665 }
7666 }
7667
7668 flush_pending!();
7669 if !have_dict {
7670 emit!(self, Instruction::BuildMap { count: 0 });
7671 }
7672
7673 Ok(())
7674 }
7675
7676 fn compile_yield_from_sequence(&mut self, is_await: bool) -> CompileResult<BlockIdx> {
7691 let send_block = self.new_block();
7692 let fail_block = self.new_block();
7693 let exit_block = self.new_block();
7694
7695 self.switch_to_block(send_block);
7697 emit!(self, Instruction::Send { delta: exit_block });
7698
7699 emit!(self, PseudoInstruction::SetupFinally { delta: fail_block });
7701 self.push_fblock(
7702 FBlockType::TryExcept, send_block,
7704 exit_block,
7705 )?;
7706
7707 emit!(self, Instruction::YieldValue { arg: 1 });
7709
7710 emit!(self, PseudoInstruction::PopBlock);
7712 self.pop_fblock(FBlockType::TryExcept);
7713
7714 emit!(
7716 self,
7717 Instruction::Resume {
7718 context: if is_await {
7719 oparg::ResumeContext::from(oparg::ResumeLocation::AfterAwait)
7720 } else {
7721 oparg::ResumeContext::from(oparg::ResumeLocation::AfterYieldFrom)
7722 }
7723 }
7724 );
7725
7726 emit!(
7728 self,
7729 PseudoInstruction::JumpNoInterrupt { delta: send_block }
7730 );
7731
7732 self.switch_to_block(fail_block);
7737 emit!(self, Instruction::CleanupThrow);
7738 self.switch_to_block(exit_block);
7744 emit!(self, Instruction::EndSend);
7745
7746 Ok(send_block)
7747 }
7748
7749 fn is_const_expression(expr: &ast::Expr) -> bool {
7751 matches!(
7752 expr,
7753 ast::Expr::StringLiteral(_)
7754 | ast::Expr::BytesLiteral(_)
7755 | ast::Expr::NumberLiteral(_)
7756 | ast::Expr::BooleanLiteral(_)
7757 | ast::Expr::NoneLiteral(_)
7758 | ast::Expr::EllipsisLiteral(_)
7759 ) || matches!(expr, ast::Expr::FString(fstring) if Self::fstring_value_is_const(&fstring.value))
7760 }
7761
7762 fn fstring_value_is_const(fstring: &ast::FStringValue) -> bool {
7763 for part in fstring {
7764 if !Self::fstring_part_is_const(part) {
7765 return false;
7766 }
7767 }
7768 true
7769 }
7770
7771 fn fstring_part_is_const(part: &ast::FStringPart) -> bool {
7772 match part {
7773 ast::FStringPart::Literal(_) => true,
7774 ast::FStringPart::FString(fstring) => fstring
7775 .elements
7776 .iter()
7777 .all(|element| matches!(element, ast::InterpolatedStringElement::Literal(_))),
7778 }
7779 }
7780
7781 fn compile_expression(&mut self, expression: &ast::Expr) -> CompileResult<()> {
7782 trace!("Compiling {expression:?}");
7783 let range = expression.range();
7784 self.set_source_range(range);
7785
7786 match &expression {
7787 ast::Expr::Call(ast::ExprCall {
7788 func, arguments, ..
7789 }) => self.compile_call(func, arguments)?,
7790 ast::Expr::BoolOp(ast::ExprBoolOp { op, values, .. }) => {
7791 self.compile_bool_op(op, values)?
7792 }
7793 ast::Expr::BinOp(ast::ExprBinOp {
7794 left, op, right, ..
7795 }) => {
7796 if matches!(op, ast::Operator::Mod)
7798 && let ast::Expr::StringLiteral(s) = left.as_ref()
7799 && let ast::Expr::Tuple(ast::ExprTuple { elts, .. }) = right.as_ref()
7800 && !elts.iter().any(|e| matches!(e, ast::Expr::Starred(_)))
7801 && self.try_optimize_format_str(s.value.to_str(), elts, range)?
7802 {
7803 return Ok(());
7804 }
7805 self.compile_expression(left)?;
7806 self.compile_expression(right)?;
7807
7808 self.set_source_range(range);
7810 self.compile_op(op, false);
7811 }
7812 ast::Expr::Subscript(ast::ExprSubscript {
7813 value, slice, ctx, ..
7814 }) => {
7815 self.compile_subscript(value, slice, *ctx)?;
7816 }
7817 ast::Expr::UnaryOp(ast::ExprUnaryOp { op, operand, .. }) => {
7818 self.compile_expression(operand)?;
7819
7820 self.set_source_range(range);
7822 match op {
7823 ast::UnaryOp::UAdd => emit!(
7824 self,
7825 Instruction::CallIntrinsic1 {
7826 func: bytecode::IntrinsicFunction1::UnaryPositive
7827 }
7828 ),
7829 ast::UnaryOp::USub => emit!(self, Instruction::UnaryNegative),
7830 ast::UnaryOp::Not => {
7831 emit!(self, Instruction::ToBool);
7832 emit!(self, Instruction::UnaryNot);
7833 }
7834 ast::UnaryOp::Invert => emit!(self, Instruction::UnaryInvert),
7835 };
7836 }
7837 ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) => {
7838 if let Some(super_type) = self.can_optimize_super_call(value, attr.as_str()) {
7840 let super_range = value.range();
7844 self.set_source_range(super_range);
7845 self.load_args_for_super(&super_type)?;
7846 self.set_source_range(super_range);
7847 let idx = self.name(attr.as_str());
7848 match super_type {
7849 SuperCallType::TwoArg { .. } => {
7850 self.emit_load_super_attr(idx);
7851 }
7852 SuperCallType::ZeroArg => {
7853 self.emit_load_zero_super_attr(idx);
7854 }
7855 }
7856 } else {
7857 self.compile_expression(value)?;
7859 let idx = self.name(attr.as_str());
7860 self.emit_load_attr(idx);
7861 }
7862 }
7863 ast::Expr::Compare(ast::ExprCompare {
7864 left,
7865 ops,
7866 comparators,
7867 ..
7868 }) => {
7869 self.compile_compare(left, ops, comparators)?;
7870 }
7871 ast::Expr::List(ast::ExprList { elts, .. }) => {
7875 self.starunpack_helper(elts, 0, CollectionType::List)?;
7876 }
7877 ast::Expr::Tuple(ast::ExprTuple { elts, .. }) => {
7878 self.starunpack_helper(elts, 0, CollectionType::Tuple)?;
7879 }
7880 ast::Expr::Set(ast::ExprSet { elts, .. }) => {
7881 self.starunpack_helper(elts, 0, CollectionType::Set)?;
7882 }
7883 ast::Expr::Dict(ast::ExprDict { items, .. }) => {
7884 self.compile_dict(items)?;
7885 }
7886 ast::Expr::Slice(ast::ExprSlice {
7887 lower, upper, step, ..
7888 }) => {
7889 if self.try_fold_constant_slice(
7891 lower.as_deref(),
7892 upper.as_deref(),
7893 step.as_deref(),
7894 )? {
7895 return Ok(());
7896 }
7897 let mut compile_bound = |bound: Option<&ast::Expr>| match bound {
7898 Some(exp) => self.compile_expression(exp),
7899 None => {
7900 self.emit_load_const(ConstantData::None);
7901 Ok(())
7902 }
7903 };
7904 compile_bound(lower.as_deref())?;
7905 compile_bound(upper.as_deref())?;
7906 if let Some(step) = step {
7907 self.compile_expression(step)?;
7908 }
7909 let argc = match step {
7910 Some(_) => BuildSliceArgCount::Three,
7911 None => BuildSliceArgCount::Two,
7912 };
7913 emit!(self, Instruction::BuildSlice { argc });
7914 }
7915 ast::Expr::Yield(ast::ExprYield { value, .. }) => {
7916 if !self.ctx.in_func() {
7917 return Err(self.error(CodegenErrorType::InvalidYield));
7918 }
7919 self.mark_generator();
7920 match value {
7921 Some(expression) => self.compile_expression(expression)?,
7922 Option::None => self.emit_load_const(ConstantData::None),
7923 };
7924 if self.ctx.func == FunctionContext::AsyncFunction {
7925 emit!(
7926 self,
7927 Instruction::CallIntrinsic1 {
7928 func: bytecode::IntrinsicFunction1::AsyncGenWrap
7929 }
7930 );
7931 }
7932 emit!(self, Instruction::YieldValue { arg: 0 });
7934 emit!(
7935 self,
7936 Instruction::Resume {
7937 context: oparg::ResumeContext::from(oparg::ResumeLocation::AfterYield)
7938 }
7939 );
7940 }
7941 ast::Expr::Await(ast::ExprAwait { value, .. }) => {
7942 if self.ctx.func != FunctionContext::AsyncFunction {
7943 return Err(self.error(CodegenErrorType::InvalidAwait));
7944 }
7945 self.compile_expression(value)?;
7946 emit!(self, Instruction::GetAwaitable { r#where: 0 });
7947 self.emit_load_const(ConstantData::None);
7948 let _ = self.compile_yield_from_sequence(true)?;
7949 }
7950 ast::Expr::YieldFrom(ast::ExprYieldFrom { value, .. }) => {
7951 match self.ctx.func {
7952 FunctionContext::NoFunction => {
7953 return Err(self.error(CodegenErrorType::InvalidYieldFrom));
7954 }
7955 FunctionContext::AsyncFunction => {
7956 return Err(self.error(CodegenErrorType::AsyncYieldFrom));
7957 }
7958 FunctionContext::Function => {}
7959 }
7960 self.mark_generator();
7961 self.compile_expression(value)?;
7962 emit!(self, Instruction::GetYieldFromIter);
7963 self.emit_load_const(ConstantData::None);
7964 let _ = self.compile_yield_from_sequence(false)?;
7965 }
7966 ast::Expr::Name(ast::ExprName { id, .. }) => self.load_name(id.as_str())?,
7967 ast::Expr::Lambda(ast::ExprLambda {
7968 parameters, body, ..
7969 }) => {
7970 let default_params = ast::Parameters::default();
7971 let params = parameters.as_deref().unwrap_or(&default_params);
7972 validate_duplicate_params(params).map_err(|e| self.error(e))?;
7973
7974 let prev_ctx = self.ctx;
7975 let name = "<lambda>".to_owned();
7976
7977 let defaults: Vec<_> = core::iter::empty()
7979 .chain(¶ms.posonlyargs)
7980 .chain(¶ms.args)
7981 .filter_map(|x| x.default.as_deref())
7982 .collect();
7983 let have_defaults = !defaults.is_empty();
7984
7985 if have_defaults {
7986 let size = defaults.len().to_u32();
7987 for element in &defaults {
7988 self.compile_expression(element)?;
7989 }
7990 emit!(self, Instruction::BuildTuple { count: size });
7991 }
7992
7993 let mut kw_with_defaults = vec![];
7995 for kwonlyarg in ¶ms.kwonlyargs {
7996 if let Some(default) = &kwonlyarg.default {
7997 kw_with_defaults.push((&kwonlyarg.parameter, default));
7998 }
7999 }
8000
8001 let have_kwdefaults = !kw_with_defaults.is_empty();
8002 if have_kwdefaults {
8003 let default_kw_count = kw_with_defaults.len();
8004 for (arg, default) in &kw_with_defaults {
8005 self.emit_load_const(ConstantData::Str {
8006 value: self.mangle(arg.name.as_str()).into_owned().into(),
8007 });
8008 self.compile_expression(default)?;
8009 }
8010 emit!(
8011 self,
8012 Instruction::BuildMap {
8013 count: default_kw_count.to_u32(),
8014 }
8015 );
8016 }
8017
8018 self.enter_function(&name, params)?;
8019 let mut func_flags = bytecode::MakeFunctionFlags::new();
8020 if have_defaults {
8021 func_flags.insert(bytecode::MakeFunctionFlag::Defaults);
8022 }
8023 if have_kwdefaults {
8024 func_flags.insert(bytecode::MakeFunctionFlag::KwOnlyDefaults);
8025 }
8026
8027 self.set_qualname();
8029
8030 self.ctx = CompileContext {
8031 loop_data: Option::None,
8032 in_class: prev_ctx.in_class,
8033 func: FunctionContext::Function,
8034 in_async_scope: false,
8036 };
8037
8038 self.compile_expression(body)?;
8041 self.emit_return_value();
8042 let code = self.exit_scope();
8043
8044 self.make_closure(code, func_flags)?;
8046
8047 self.ctx = prev_ctx;
8048 }
8049 ast::Expr::ListComp(ast::ExprListComp {
8050 elt, generators, ..
8051 }) => {
8052 self.compile_comprehension(
8053 "<listcomp>",
8054 Some(
8055 Instruction::BuildList {
8056 count: OpArgMarker::marker(),
8057 }
8058 .into(),
8059 ),
8060 generators,
8061 &|compiler| {
8062 compiler.compile_comprehension_element(elt)?;
8063 emit!(
8064 compiler,
8065 Instruction::ListAppend {
8066 i: (generators.len() + 1).to_u32(),
8067 }
8068 );
8069 Ok(())
8070 },
8071 ComprehensionType::List,
8072 Self::contains_await(elt) || Self::generators_contain_await(generators),
8073 )?;
8074 }
8075 ast::Expr::SetComp(ast::ExprSetComp {
8076 elt, generators, ..
8077 }) => {
8078 self.compile_comprehension(
8079 "<setcomp>",
8080 Some(
8081 Instruction::BuildSet {
8082 count: OpArgMarker::marker(),
8083 }
8084 .into(),
8085 ),
8086 generators,
8087 &|compiler| {
8088 compiler.compile_comprehension_element(elt)?;
8089 emit!(
8090 compiler,
8091 Instruction::SetAdd {
8092 i: (generators.len() + 1).to_u32(),
8093 }
8094 );
8095 Ok(())
8096 },
8097 ComprehensionType::Set,
8098 Self::contains_await(elt) || Self::generators_contain_await(generators),
8099 )?;
8100 }
8101 ast::Expr::DictComp(ast::ExprDictComp {
8102 key,
8103 value,
8104 generators,
8105 ..
8106 }) => {
8107 self.compile_comprehension(
8108 "<dictcomp>",
8109 Some(
8110 Instruction::BuildMap {
8111 count: OpArgMarker::marker(),
8112 }
8113 .into(),
8114 ),
8115 generators,
8116 &|compiler| {
8117 compiler.compile_expression(key)?;
8119 compiler.compile_expression(value)?;
8120
8121 emit!(
8122 compiler,
8123 Instruction::MapAdd {
8124 i: (generators.len() + 1).to_u32(),
8125 }
8126 );
8127
8128 Ok(())
8129 },
8130 ComprehensionType::Dict,
8131 Self::contains_await(key)
8132 || Self::contains_await(value)
8133 || Self::generators_contain_await(generators),
8134 )?;
8135 }
8136 ast::Expr::Generator(ast::ExprGenerator {
8137 elt, generators, ..
8138 }) => {
8139 let element_contains_await =
8142 Self::contains_await(elt) || Self::generators_contain_await(generators);
8143 self.compile_comprehension(
8144 "<genexpr>",
8145 None,
8146 generators,
8147 &|compiler| {
8148 compiler.compile_comprehension_element(elt)?;
8152
8153 compiler.mark_generator();
8154 if compiler.ctx.func == FunctionContext::AsyncFunction {
8155 emit!(
8156 compiler,
8157 Instruction::CallIntrinsic1 {
8158 func: bytecode::IntrinsicFunction1::AsyncGenWrap
8159 }
8160 );
8161 }
8162 emit!(compiler, Instruction::YieldValue { arg: 0 });
8164 emit!(
8165 compiler,
8166 Instruction::Resume {
8167 context: oparg::ResumeContext::from(
8168 oparg::ResumeLocation::AfterYield
8169 )
8170 }
8171 );
8172 emit!(compiler, Instruction::PopTop);
8173
8174 Ok(())
8175 },
8176 ComprehensionType::Generator,
8177 element_contains_await,
8178 )?;
8179 }
8180 ast::Expr::Starred(ast::ExprStarred { value, .. }) => {
8181 if self.in_annotation {
8182 self.compile_expression(value)?;
8186 } else {
8187 return Err(self.error(CodegenErrorType::InvalidStarExpr));
8188 }
8189 }
8190 ast::Expr::If(ast::ExprIf {
8191 test, body, orelse, ..
8192 }) => {
8193 let else_block = self.new_block();
8194 let after_block = self.new_block();
8195 self.compile_jump_if(test, false, else_block)?;
8196
8197 self.compile_expression(body)?;
8199 emit!(self, PseudoInstruction::Jump { delta: after_block });
8200
8201 self.switch_to_block(else_block);
8203 self.compile_expression(orelse)?;
8204
8205 self.switch_to_block(after_block);
8207 }
8208
8209 ast::Expr::Named(ast::ExprNamed {
8210 target,
8211 value,
8212 node_index: _,
8213 range: _,
8214 }) => {
8215 if self.current_code_info().in_inlined_comp
8217 && let ast::Expr::Name(ast::ExprName { id, .. }) = target.as_ref()
8218 {
8219 let name = self.mangle(id.as_str());
8220 let info = self.code_stack.last_mut().unwrap();
8221 info.metadata.fast_hidden.insert(name.to_string(), false);
8222 }
8223 self.compile_expression(value)?;
8224 emit!(self, Instruction::Copy { i: 1 });
8225 self.compile_store(target)?;
8226 }
8227 ast::Expr::FString(fstring) => {
8228 self.compile_expr_fstring(fstring)?;
8229 }
8230 ast::Expr::TString(tstring) => {
8231 self.compile_expr_tstring(tstring)?;
8232 }
8233 ast::Expr::StringLiteral(string) => {
8234 let value = self.compile_string_value(string);
8235 self.emit_load_const(ConstantData::Str { value });
8236 }
8237 ast::Expr::BytesLiteral(bytes) => {
8238 let iter = bytes.value.iter().flat_map(|x| x.iter().copied());
8239 let v: Vec<u8> = iter.collect();
8240 self.emit_load_const(ConstantData::Bytes { value: v });
8241 }
8242 ast::Expr::NumberLiteral(number) => match &number.value {
8243 ast::Number::Int(int) => {
8244 let value = ruff_int_to_bigint(int).map_err(|e| self.error(e))?;
8245 self.emit_load_const(ConstantData::Integer { value });
8246 }
8247 ast::Number::Float(float) => {
8248 self.emit_load_const(ConstantData::Float { value: *float });
8249 }
8250 ast::Number::Complex { real, imag } => {
8251 self.emit_load_const(ConstantData::Complex {
8252 value: Complex::new(*real, *imag),
8253 });
8254 }
8255 },
8256 ast::Expr::BooleanLiteral(b) => {
8257 self.emit_load_const(ConstantData::Boolean { value: b.value });
8258 }
8259 ast::Expr::NoneLiteral(_) => {
8260 self.emit_load_const(ConstantData::None);
8261 }
8262 ast::Expr::EllipsisLiteral(_) => {
8263 self.emit_load_const(ConstantData::Ellipsis);
8264 }
8265 ast::Expr::IpyEscapeCommand(_) => {
8266 panic!("unexpected ipy escape command");
8267 }
8268 }
8269 Ok(())
8270 }
8271
8272 fn compile_keywords(&mut self, keywords: &[ast::Keyword]) -> CompileResult<()> {
8273 let mut size = 0;
8274 let groupby = keywords.iter().chunk_by(|e| e.arg.is_none());
8275 for (is_unpacking, sub_keywords) in &groupby {
8276 if is_unpacking {
8277 for keyword in sub_keywords {
8278 self.compile_expression(&keyword.value)?;
8279 size += 1;
8280 }
8281 } else {
8282 let mut sub_size = 0;
8283 for keyword in sub_keywords {
8284 if let Some(name) = &keyword.arg {
8285 self.emit_load_const(ConstantData::Str {
8286 value: name.as_str().into(),
8287 });
8288 self.compile_expression(&keyword.value)?;
8289 sub_size += 1;
8290 }
8291 }
8292 emit!(self, Instruction::BuildMap { count: sub_size });
8293 size += 1;
8294 }
8295 }
8296 if size > 1 {
8297 for _ in 1..size {
8299 emit!(self, Instruction::DictMerge { i: 1 });
8300 }
8301 }
8302 Ok(())
8303 }
8304
8305 fn detect_builtin_generator_call(
8306 &self,
8307 func: &ast::Expr,
8308 args: &ast::Arguments,
8309 ) -> Option<BuiltinGeneratorCallKind> {
8310 let ast::Expr::Name(ast::ExprName { id, .. }) = func else {
8311 return None;
8312 };
8313 if args.args.len() != 1
8314 || !args.keywords.is_empty()
8315 || !matches!(args.args[0], ast::Expr::Generator(_))
8316 {
8317 return None;
8318 }
8319 match id.as_str() {
8320 "tuple" => Some(BuiltinGeneratorCallKind::Tuple),
8321 "list" => Some(BuiltinGeneratorCallKind::List),
8322 "set" => Some(BuiltinGeneratorCallKind::Set),
8323 "all" => Some(BuiltinGeneratorCallKind::All),
8324 "any" => Some(BuiltinGeneratorCallKind::Any),
8325 _ => None,
8326 }
8327 }
8328
8329 fn optimize_builtin_generator_call(
8336 &mut self,
8337 kind: BuiltinGeneratorCallKind,
8338 end: BlockIdx,
8339 ) -> CompileResult<()> {
8340 let common_constant = match kind {
8341 BuiltinGeneratorCallKind::Tuple => bytecode::CommonConstant::BuiltinTuple,
8342 BuiltinGeneratorCallKind::List => bytecode::CommonConstant::BuiltinList,
8343 BuiltinGeneratorCallKind::Set => bytecode::CommonConstant::BuiltinSet,
8344 BuiltinGeneratorCallKind::All => bytecode::CommonConstant::BuiltinAll,
8345 BuiltinGeneratorCallKind::Any => bytecode::CommonConstant::BuiltinAny,
8346 };
8347
8348 let loop_block = self.new_block();
8349 let cleanup = self.new_block();
8350 let fallback = self.new_block();
8351 let result = matches!(
8352 kind,
8353 BuiltinGeneratorCallKind::All | BuiltinGeneratorCallKind::Any
8354 )
8355 .then(|| self.new_block());
8356
8357 emit!(self, Instruction::Copy { i: 2 });
8359 emit!(
8360 self,
8361 Instruction::LoadCommonConstant {
8362 idx: common_constant
8363 }
8364 );
8365 emit!(self, Instruction::IsOp { invert: Invert::No });
8366 emit!(self, Instruction::PopJumpIfFalse { delta: fallback });
8367 emit!(self, Instruction::NotTaken);
8368 emit!(self, Instruction::Swap { i: 2 });
8370 emit!(self, Instruction::PopTop);
8371
8372 if matches!(
8373 kind,
8374 BuiltinGeneratorCallKind::Tuple | BuiltinGeneratorCallKind::List
8375 ) {
8376 emit!(self, Instruction::BuildList { count: 0 });
8378 emit!(self, Instruction::Swap { i: 2 });
8379 } else if matches!(kind, BuiltinGeneratorCallKind::Set) {
8380 emit!(self, Instruction::BuildSet { count: 0 });
8382 emit!(self, Instruction::Swap { i: 2 });
8383 }
8384
8385 self.switch_to_block(loop_block);
8386 emit!(self, Instruction::ForIter { delta: cleanup });
8387
8388 match kind {
8389 BuiltinGeneratorCallKind::Tuple | BuiltinGeneratorCallKind::List => {
8390 emit!(self, Instruction::ListAppend { i: 2 });
8391 emit!(self, PseudoInstruction::Jump { delta: loop_block });
8392 }
8393 BuiltinGeneratorCallKind::Set => {
8394 emit!(self, Instruction::SetAdd { i: 2 });
8395 emit!(self, PseudoInstruction::Jump { delta: loop_block });
8396 }
8397 BuiltinGeneratorCallKind::All => {
8398 let result = result.expect("all() optimization should have a result block");
8399 emit!(self, Instruction::ToBool);
8400 emit!(self, Instruction::PopJumpIfFalse { delta: result });
8401 emit!(self, Instruction::NotTaken);
8402 emit!(self, PseudoInstruction::Jump { delta: loop_block });
8403 }
8404 BuiltinGeneratorCallKind::Any => {
8405 let result = result.expect("any() optimization should have a result block");
8406 emit!(self, Instruction::ToBool);
8407 emit!(self, Instruction::PopJumpIfTrue { delta: result });
8408 emit!(self, Instruction::NotTaken);
8409 emit!(self, PseudoInstruction::Jump { delta: loop_block });
8410 }
8411 }
8412
8413 if let Some(result_block) = result {
8414 self.switch_to_block(result_block);
8415 emit!(self, Instruction::PopIter);
8416 self.emit_load_const(ConstantData::Boolean {
8417 value: matches!(kind, BuiltinGeneratorCallKind::Any),
8418 });
8419 emit!(self, PseudoInstruction::Jump { delta: end });
8420 }
8421
8422 self.switch_to_block(cleanup);
8423 emit!(self, Instruction::EndFor);
8424 emit!(self, Instruction::PopIter);
8425 match kind {
8426 BuiltinGeneratorCallKind::Tuple => {
8427 emit!(
8428 self,
8429 Instruction::CallIntrinsic1 {
8430 func: IntrinsicFunction1::ListToTuple
8431 }
8432 );
8433 }
8434 BuiltinGeneratorCallKind::List | BuiltinGeneratorCallKind::Set => {}
8435 BuiltinGeneratorCallKind::All => {
8436 self.emit_load_const(ConstantData::Boolean { value: true });
8437 }
8438 BuiltinGeneratorCallKind::Any => {
8439 self.emit_load_const(ConstantData::Boolean { value: false });
8440 }
8441 }
8442 emit!(self, PseudoInstruction::Jump { delta: end });
8443
8444 self.switch_to_block(fallback);
8445 Ok(())
8446 }
8447
8448 fn compile_call(&mut self, func: &ast::Expr, args: &ast::Arguments) -> CompileResult<()> {
8449 let call_range = self.current_source_range;
8452 let uses_ex_call = self.call_uses_ex_call(args);
8453
8454 if let ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = &func {
8457 if !uses_ex_call
8459 && let Some(super_type) = self.can_optimize_super_call(value, attr.as_str())
8460 {
8461 let super_range = value.range();
8465 self.set_source_range(super_range);
8466 self.load_args_for_super(&super_type)?;
8467 self.set_source_range(super_range);
8468 let idx = self.name(attr.as_str());
8469 match super_type {
8470 SuperCallType::TwoArg { .. } => {
8471 self.emit_load_super_method(idx);
8472 }
8473 SuperCallType::ZeroArg => {
8474 self.emit_load_zero_super_method(idx);
8475 }
8476 }
8477 self.set_source_range(attr.range());
8479 emit!(self, Instruction::Nop);
8480 self.codegen_call_helper(0, args, attr.range())?;
8482 } else {
8483 self.compile_expression(value)?;
8484 let idx = self.name(attr.as_str());
8485 let is_import = matches!(value.as_ref(), ast::Expr::Name(ast::ExprName { id, .. })
8489 if self.is_name_imported(id.as_str()));
8490 if is_import || uses_ex_call {
8491 self.emit_load_attr(idx);
8492 emit!(self, Instruction::PushNull);
8493 } else {
8494 self.emit_load_attr_method(idx);
8495 }
8496 self.codegen_call_helper(0, args, call_range)?;
8497 }
8498 } else if let Some(kind) = (!uses_ex_call)
8499 .then(|| self.detect_builtin_generator_call(func, args))
8500 .flatten()
8501 {
8502 let end = self.new_block();
8505 self.compile_expression(func)?;
8506 self.compile_expression(&args.args[0])?;
8507 self.optimize_builtin_generator_call(kind, end)?;
8509 emit!(self, Instruction::PushNull);
8511 emit!(self, Instruction::Swap { i: 2 });
8512 self.set_source_range(call_range);
8513 emit!(self, Instruction::Call { argc: 1 });
8514 self.switch_to_block(end);
8515 } else {
8516 self.compile_expression(func)?;
8519 emit!(self, Instruction::PushNull);
8520 self.codegen_call_helper(0, args, call_range)?;
8521 }
8522 Ok(())
8523 }
8524
8525 fn call_uses_ex_call(&self, arguments: &ast::Arguments) -> bool {
8526 let has_starred = arguments
8527 .args
8528 .iter()
8529 .any(|arg| matches!(arg, ast::Expr::Starred(_)));
8530 let has_double_star = arguments.keywords.iter().any(|k| k.arg.is_none());
8531 let too_big = arguments.args.len() + arguments.keywords.len() > 15;
8532 has_starred || has_double_star || too_big
8533 }
8534
8535 fn codegen_subkwargs(
8537 &mut self,
8538 keywords: &[ast::Keyword],
8539 begin: usize,
8540 end: usize,
8541 ) -> CompileResult<()> {
8542 let n = end - begin;
8543 assert!(n > 0);
8544
8545 let big = n * 2 > 8; if big {
8549 emit!(self, Instruction::BuildMap { count: 0 });
8550 }
8551
8552 for kw in &keywords[begin..end] {
8553 self.emit_load_const(ConstantData::Str {
8555 value: kw.arg.as_ref().unwrap().as_str().into(),
8556 });
8557 self.compile_expression(&kw.value)?;
8558
8559 if big {
8560 emit!(self, Instruction::MapAdd { i: 1 });
8561 }
8562 }
8563
8564 if !big {
8565 emit!(self, Instruction::BuildMap { count: n.to_u32() });
8566 }
8567
8568 Ok(())
8569 }
8570
8571 fn codegen_call_helper(
8575 &mut self,
8576 additional_positional: u32,
8577 arguments: &ast::Arguments,
8578 call_range: TextRange,
8579 ) -> CompileResult<()> {
8580 let nelts = arguments.args.len();
8581 let nkwelts = arguments.keywords.len();
8582
8583 let has_starred = arguments
8585 .args
8586 .iter()
8587 .any(|arg| matches!(arg, ast::Expr::Starred(_)));
8588 let has_double_star = arguments.keywords.iter().any(|k| k.arg.is_none());
8589
8590 let too_big = nelts + nkwelts > 15;
8594
8595 if !has_starred && !has_double_star && !too_big {
8596 for arg in &arguments.args {
8598 self.compile_expression(arg)?;
8599 }
8600
8601 if nkwelts > 0 {
8602 let mut kwarg_names = Vec::with_capacity(nkwelts);
8604 for keyword in &arguments.keywords {
8605 kwarg_names.push(ConstantData::Str {
8606 value: keyword.arg.as_ref().unwrap().as_str().into(),
8607 });
8608 self.compile_expression(&keyword.value)?;
8609 }
8610
8611 self.set_source_range(call_range);
8613 self.emit_load_const(ConstantData::Tuple {
8614 elements: kwarg_names,
8615 });
8616
8617 let argc = additional_positional + nelts.to_u32() + nkwelts.to_u32();
8618 emit!(self, Instruction::CallKw { argc });
8619 } else {
8620 self.set_source_range(call_range);
8621 let argc = additional_positional + nelts.to_u32();
8622 emit!(self, Instruction::Call { argc });
8623 }
8624 } else {
8625 if additional_positional == 0
8629 && nelts == 1
8630 && matches!(arguments.args[0], ast::Expr::Starred(_))
8631 {
8632 if let ast::Expr::Starred(ast::ExprStarred { value, .. }) = &arguments.args[0] {
8635 self.compile_expression(value)?;
8636 }
8637 } else if !has_starred {
8638 for arg in &arguments.args {
8639 self.compile_expression(arg)?;
8640 }
8641 self.set_source_range(call_range);
8642 let positional_count = additional_positional + nelts.to_u32();
8643 if positional_count == 0 {
8644 self.emit_load_const(ConstantData::Tuple { elements: vec![] });
8645 } else {
8646 emit!(
8647 self,
8648 Instruction::BuildTuple {
8649 count: positional_count
8650 }
8651 );
8652 }
8653 } else {
8654 self.starunpack_helper(
8656 &arguments.args,
8657 additional_positional,
8658 CollectionType::List,
8659 )?;
8660 emit!(
8661 self,
8662 Instruction::CallIntrinsic1 {
8663 func: IntrinsicFunction1::ListToTuple
8664 }
8665 );
8666 }
8667
8668 if nkwelts > 0 {
8670 let mut have_dict = false;
8671 let mut nseen = 0usize;
8672
8673 for (i, keyword) in arguments.keywords.iter().enumerate() {
8674 if keyword.arg.is_none() {
8675 if nseen > 0 {
8677 self.codegen_subkwargs(&arguments.keywords, i - nseen, i)?;
8679 if have_dict {
8680 emit!(self, Instruction::DictMerge { i: 1 });
8681 }
8682 have_dict = true;
8683 nseen = 0;
8684 }
8685
8686 if !have_dict {
8687 emit!(self, Instruction::BuildMap { count: 0 });
8688 have_dict = true;
8689 }
8690
8691 self.compile_expression(&keyword.value)?;
8692 emit!(self, Instruction::DictMerge { i: 1 });
8693 } else {
8694 nseen += 1;
8695 }
8696 }
8697
8698 if nseen > 0 {
8700 self.codegen_subkwargs(&arguments.keywords, nkwelts - nseen, nkwelts)?;
8701 if have_dict {
8702 emit!(self, Instruction::DictMerge { i: 1 });
8703 }
8704 have_dict = true;
8705 }
8706
8707 assert!(have_dict);
8708 } else {
8709 emit!(self, Instruction::PushNull);
8710 }
8711
8712 self.set_source_range(call_range);
8713 emit!(self, Instruction::CallFunctionEx);
8714 }
8715
8716 Ok(())
8717 }
8718
8719 fn compile_comprehension_element(&mut self, element: &ast::Expr) -> CompileResult<()> {
8720 self.compile_expression(element).map_err(|e| {
8721 if let CodegenErrorType::InvalidStarExpr = e.error {
8722 self.error(CodegenErrorType::SyntaxError(
8723 "iterable unpacking cannot be used in comprehension".to_owned(),
8724 ))
8725 } else {
8726 e
8727 }
8728 })
8729 }
8730
8731 fn consume_next_sub_table(&mut self) -> CompileResult<()> {
8732 {
8733 let _ = self.push_symbol_table()?;
8734 }
8735 let _ = self.pop_symbol_table();
8736 Ok(())
8737 }
8738
8739 fn consume_skipped_nested_scopes_in_expr(
8740 &mut self,
8741 expression: &ast::Expr,
8742 ) -> CompileResult<()> {
8743 use ast::visitor::Visitor;
8744
8745 struct SkippedScopeVisitor<'a> {
8746 compiler: &'a mut Compiler,
8747 error: Option<CodegenError>,
8748 }
8749
8750 impl SkippedScopeVisitor<'_> {
8751 fn consume_scope(&mut self) {
8752 if self.error.is_none() {
8753 self.error = self.compiler.consume_next_sub_table().err();
8754 }
8755 }
8756 }
8757
8758 impl ast::visitor::Visitor<'_> for SkippedScopeVisitor<'_> {
8759 fn visit_expr(&mut self, expr: &ast::Expr) {
8760 if self.error.is_some() {
8761 return;
8762 }
8763
8764 match expr {
8765 ast::Expr::Lambda(ast::ExprLambda { parameters, .. }) => {
8766 if let Some(params) = parameters.as_deref() {
8770 for default in params
8771 .posonlyargs
8772 .iter()
8773 .chain(¶ms.args)
8774 .chain(¶ms.kwonlyargs)
8775 .filter_map(|p| p.default.as_deref())
8776 {
8777 self.visit_expr(default);
8778 }
8779 }
8780 self.consume_scope();
8781 }
8782 ast::Expr::ListComp(ast::ExprListComp { generators, .. })
8783 | ast::Expr::SetComp(ast::ExprSetComp { generators, .. })
8784 | ast::Expr::Generator(ast::ExprGenerator { generators, .. }) => {
8785 self.consume_scope();
8790 if let Some(first) = generators.first() {
8791 self.visit_expr(&first.iter);
8792 }
8793 }
8794 ast::Expr::DictComp(ast::ExprDictComp { generators, .. }) => {
8795 self.consume_scope();
8796 if let Some(first) = generators.first() {
8797 self.visit_expr(&first.iter);
8798 }
8799 }
8800 _ => ast::visitor::walk_expr(self, expr),
8801 }
8802 }
8803 }
8804
8805 let mut visitor = SkippedScopeVisitor {
8806 compiler: self,
8807 error: None,
8808 };
8809 visitor.visit_expr(expression);
8810 if let Some(err) = visitor.error {
8811 Err(err)
8812 } else {
8813 Ok(())
8814 }
8815 }
8816
8817 fn compile_comprehension(
8818 &mut self,
8819 name: &str,
8820 init_collection: Option<AnyInstruction>,
8821 generators: &[ast::Comprehension],
8822 compile_element: &dyn Fn(&mut Self) -> CompileResult<()>,
8823 comprehension_type: ComprehensionType,
8824 element_contains_await: bool,
8825 ) -> CompileResult<()> {
8826 let prev_ctx = self.ctx;
8827 let has_an_async_gen = generators.iter().any(|g| g.is_async);
8828
8829 if comprehension_type != ComprehensionType::Generator
8832 && (has_an_async_gen || element_contains_await)
8833 && !prev_ctx.in_async_scope
8834 {
8835 return Err(self.error(CodegenErrorType::InvalidAsyncComprehension));
8836 }
8837
8838 let is_inlined = self.is_inlined_comprehension_context(comprehension_type);
8840
8841 let is_async_list_set_dict_comprehension = comprehension_type
8845 != ComprehensionType::Generator
8846 && (has_an_async_gen || element_contains_await)
8847 && prev_ctx.in_async_scope;
8848
8849 let is_async_generator_comprehension = comprehension_type == ComprehensionType::Generator
8850 && (has_an_async_gen || element_contains_await);
8851
8852 debug_assert!(!(is_async_list_set_dict_comprehension && is_async_generator_comprehension));
8853
8854 let is_async = is_async_list_set_dict_comprehension || is_async_generator_comprehension;
8855
8856 assert!(!generators.is_empty());
8858
8859 if is_inlined && !has_an_async_gen && !element_contains_await {
8860 let was_in_inlined_comp = self.current_code_info().in_inlined_comp;
8862 self.current_code_info().in_inlined_comp = true;
8863 let result = self.compile_inlined_comprehension(
8864 init_collection,
8865 generators,
8866 compile_element,
8867 has_an_async_gen,
8868 );
8869 self.current_code_info().in_inlined_comp = was_in_inlined_comp;
8870 return result;
8871 }
8872
8873 self.ctx = CompileContext {
8875 loop_data: None,
8876 in_class: prev_ctx.in_class,
8877 func: if is_async {
8878 FunctionContext::AsyncFunction
8879 } else {
8880 FunctionContext::Function
8881 },
8882 in_async_scope: prev_ctx.in_async_scope || is_async,
8885 };
8886
8887 let flags = bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED;
8888 let flags = if is_async {
8889 flags | bytecode::CodeFlags::COROUTINE
8890 } else {
8891 flags
8892 };
8893
8894 self.push_output(flags, 1, 1, 0, name.to_owned())?;
8896
8897 self.set_qualname();
8899
8900 let arg0 = self.varname(".0")?;
8901
8902 let return_none = init_collection.is_none();
8903
8904 let is_gen_scope = self.current_symbol_table().is_generator || is_async;
8906 let stop_iteration_block = if is_gen_scope {
8907 let handler_block = self.new_block();
8908 emit!(
8909 self,
8910 PseudoInstruction::SetupCleanup {
8911 delta: handler_block
8912 }
8913 );
8914 self.set_no_location();
8915 self.push_fblock(FBlockType::StopIteration, handler_block, handler_block)?;
8916 Some(handler_block)
8917 } else {
8918 None
8919 };
8920
8921 if let Some(init_collection) = init_collection {
8923 self._emit(init_collection, OpArg::new(0), BlockIdx::NULL)
8924 }
8925
8926 let mut loop_labels = vec![];
8927 for generator in generators {
8928 let loop_block = self.new_block();
8929 let if_cleanup_block = self.new_block();
8930 let after_block = self.new_block();
8931
8932 if loop_labels.is_empty() {
8933 emit!(self, Instruction::LoadFast { var_num: arg0 });
8935 } else {
8936 self.compile_expression(&generator.iter)?;
8938
8939 if generator.is_async {
8941 emit!(self, Instruction::GetAIter);
8942 } else {
8943 emit!(self, Instruction::GetIter);
8944 }
8945 }
8946
8947 self.switch_to_block(loop_block);
8948 let mut end_async_for_target = BlockIdx::NULL;
8949 if generator.is_async {
8950 emit!(self, PseudoInstruction::SetupFinally { delta: after_block });
8951 emit!(self, Instruction::GetANext);
8952 self.push_fblock(
8953 FBlockType::AsyncComprehensionGenerator,
8954 loop_block,
8955 after_block,
8956 )?;
8957 self.emit_load_const(ConstantData::None);
8958 end_async_for_target = self.compile_yield_from_sequence(true)?;
8959 emit!(self, PseudoInstruction::PopBlock);
8962 self.pop_fblock(FBlockType::AsyncComprehensionGenerator);
8963 self.compile_store(&generator.target)?;
8964 } else {
8965 emit!(self, Instruction::ForIter { delta: after_block });
8966 self.compile_store(&generator.target)?;
8967 }
8968 loop_labels.push((
8969 loop_block,
8970 if_cleanup_block,
8971 after_block,
8972 generator.is_async,
8973 end_async_for_target,
8974 ));
8975
8976 for if_condition in &generator.ifs {
8978 self.compile_jump_if(if_condition, false, if_cleanup_block)?
8979 }
8980 }
8981
8982 compile_element(self)?;
8983
8984 for (loop_block, if_cleanup_block, after_block, is_async, end_async_for_target) in
8985 loop_labels.iter().rev().copied()
8986 {
8987 emit!(self, PseudoInstruction::Jump { delta: loop_block });
8988
8989 self.switch_to_block(if_cleanup_block);
8990 emit!(self, PseudoInstruction::Jump { delta: loop_block });
8991
8992 self.switch_to_block(after_block);
8993 if is_async {
8994 self.emit_end_async_for(end_async_for_target);
8997 } else {
8998 emit!(self, Instruction::EndFor);
9000 emit!(self, Instruction::PopIter);
9001 }
9002 }
9003
9004 if return_none {
9005 self.emit_load_const(ConstantData::None)
9006 }
9007
9008 self.emit_return_value();
9009
9010 if let Some(handler_block) = stop_iteration_block {
9012 emit!(self, PseudoInstruction::PopBlock);
9013 self.set_no_location();
9014 self.pop_fblock(FBlockType::StopIteration);
9015 self.switch_to_block(handler_block);
9016 emit!(
9017 self,
9018 Instruction::CallIntrinsic1 {
9019 func: oparg::IntrinsicFunction1::StopIterationError
9020 }
9021 );
9022 self.set_no_location();
9023 emit!(self, Instruction::Reraise { depth: 1u32 });
9024 self.set_no_location();
9025 }
9026
9027 let code = self.exit_scope();
9028
9029 self.ctx = prev_ctx;
9030
9031 self.make_closure(code, bytecode::MakeFunctionFlags::new())?;
9033
9034 self.compile_expression(&generators[0].iter)?;
9036
9037 if generators[0].is_async {
9040 emit!(self, Instruction::GetAIter);
9041 } else {
9042 emit!(self, Instruction::GetIter);
9043 };
9044
9045 emit!(self, Instruction::Call { argc: 0 });
9047 if is_async_list_set_dict_comprehension {
9048 emit!(self, Instruction::GetAwaitable { r#where: 0 });
9049 self.emit_load_const(ConstantData::None);
9050 let _ = self.compile_yield_from_sequence(true)?;
9051 }
9052
9053 Ok(())
9054 }
9055
9056 fn compile_inlined_comprehension(
9059 &mut self,
9060 init_collection: Option<AnyInstruction>,
9061 generators: &[ast::Comprehension],
9062 compile_element: &dyn Fn(&mut Self) -> CompileResult<()>,
9063 has_async: bool,
9064 ) -> CompileResult<()> {
9065 let current_table = self
9068 .symbol_table_stack
9069 .last_mut()
9070 .expect("no current symbol table");
9071 let comp_table = current_table.sub_tables[current_table.next_sub_table].clone();
9072 current_table.next_sub_table += 1;
9073
9074 self.compile_expression(&generators[0].iter)?;
9079
9080 if !comp_table.sub_tables.is_empty() {
9083 let current_table = self
9084 .symbol_table_stack
9085 .last_mut()
9086 .expect("no current symbol table");
9087 let insert_pos = current_table.next_sub_table;
9088 for (i, st) in comp_table.sub_tables.iter().enumerate() {
9089 current_table.sub_tables.insert(insert_pos + i, st.clone());
9090 }
9091 }
9092 if has_async && generators[0].is_async {
9093 emit!(self, Instruction::GetAIter);
9094 } else {
9095 emit!(self, Instruction::GetIter);
9096 }
9097
9098 let in_class_block = {
9101 let ct = self.current_symbol_table();
9102 ct.typ == CompilerScope::Class && !self.current_code_info().in_inlined_comp
9103 };
9104 let mut pushed_locals: Vec<String> = Vec::new();
9105 for (name, sym) in &comp_table.symbols {
9106 if sym.flags.contains(SymbolFlags::PARAMETER) {
9107 continue; }
9109 let is_walrus = sym.flags.contains(SymbolFlags::ASSIGNED_IN_COMPREHENSION)
9112 && !sym.flags.contains(SymbolFlags::ITER);
9113 let is_local = sym
9114 .flags
9115 .intersects(SymbolFlags::ASSIGNED | SymbolFlags::ITER)
9116 && !sym.flags.contains(SymbolFlags::NONLOCAL)
9117 && !is_walrus;
9118 if is_local || in_class_block {
9119 pushed_locals.push(name.clone());
9120 }
9121 }
9122
9123 let mut temp_symbols: IndexMap<String, Symbol> = IndexMap::default();
9126 for (name, comp_sym) in &comp_table.symbols {
9127 if comp_sym.flags.contains(SymbolFlags::PARAMETER) {
9128 continue; }
9130 let comp_scope = comp_sym.scope;
9131
9132 let current_table = self.symbol_table_stack.last().expect("no symbol table");
9133 if let Some(outer_sym) = current_table.symbols.get(name) {
9134 let outer_scope = outer_sym.scope;
9135 if (comp_scope != outer_scope
9136 && comp_scope != SymbolScope::Free
9137 && !(comp_scope == SymbolScope::Cell && outer_scope == SymbolScope::Free))
9138 || in_class_block
9139 {
9140 temp_symbols.insert(name.clone(), outer_sym.clone());
9141 let current_table =
9142 self.symbol_table_stack.last_mut().expect("no symbol table");
9143 current_table.symbols.insert(name.clone(), comp_sym.clone());
9144 }
9145 }
9146 }
9147
9148 let mut total_stack_items: usize = 0;
9154 for name in &pushed_locals {
9155 let var_num = self.varname(name)?;
9156 emit!(self, Instruction::LoadFastAndClear { var_num });
9157 total_stack_items += 1;
9158 if let Some(comp_sym) = comp_table.symbols.get(name)
9160 && comp_sym.scope == SymbolScope::Cell
9161 {
9162 let i = if self
9163 .current_symbol_table()
9164 .symbols
9165 .get(name)
9166 .is_some_and(|s| s.scope == SymbolScope::Free)
9167 {
9168 self.get_free_var_index(name)?
9169 } else {
9170 self.get_cell_var_index(name)?
9171 };
9172 emit!(self, Instruction::MakeCell { i });
9173 }
9174 }
9175
9176 if total_stack_items > 0 {
9178 emit!(
9179 self,
9180 Instruction::Swap {
9181 i: u32::try_from(total_stack_items + 1).unwrap()
9182 }
9183 );
9184 }
9185
9186 if let Some(init_collection) = init_collection {
9188 self._emit(init_collection, OpArg::new(0), BlockIdx::NULL);
9189 emit!(self, Instruction::Swap { i: 2 });
9191 }
9192
9193 let cleanup_block = self.new_block();
9195 let end_block = self.new_block();
9196
9197 if !pushed_locals.is_empty() {
9198 emit!(
9199 self,
9200 PseudoInstruction::SetupFinally {
9201 delta: cleanup_block
9202 }
9203 );
9204 self.push_fblock(FBlockType::TryExcept, cleanup_block, end_block)?;
9205 }
9206
9207 let mut loop_labels: Vec<(BlockIdx, BlockIdx, BlockIdx, bool, BlockIdx)> = vec![];
9209 for (i, generator) in generators.iter().enumerate() {
9210 let loop_block = self.new_block();
9211 let if_cleanup_block = self.new_block();
9212 let after_block = self.new_block();
9213
9214 if i > 0 {
9215 self.compile_expression(&generator.iter)?;
9216 if generator.is_async {
9217 emit!(self, Instruction::GetAIter);
9218 } else {
9219 emit!(self, Instruction::GetIter);
9220 }
9221 }
9222
9223 self.switch_to_block(loop_block);
9224
9225 let mut end_async_for_target = BlockIdx::NULL;
9226 if generator.is_async {
9227 emit!(self, PseudoInstruction::SetupFinally { delta: after_block });
9228 emit!(self, Instruction::GetANext);
9229 self.push_fblock(
9230 FBlockType::AsyncComprehensionGenerator,
9231 loop_block,
9232 after_block,
9233 )?;
9234 self.emit_load_const(ConstantData::None);
9235 end_async_for_target = self.compile_yield_from_sequence(true)?;
9236 emit!(self, PseudoInstruction::PopBlock);
9237 self.pop_fblock(FBlockType::AsyncComprehensionGenerator);
9238 self.compile_store(&generator.target)?;
9239 } else {
9240 emit!(self, Instruction::ForIter { delta: after_block });
9241 self.compile_store(&generator.target)?;
9242 }
9243
9244 loop_labels.push((
9245 loop_block,
9246 if_cleanup_block,
9247 after_block,
9248 generator.is_async,
9249 end_async_for_target,
9250 ));
9251
9252 for if_condition in &generator.ifs {
9254 self.compile_jump_if(if_condition, false, if_cleanup_block)?;
9255 }
9256 }
9257
9258 compile_element(self)?;
9260
9261 for &(loop_block, if_cleanup_block, after_block, is_async, end_async_for_target) in
9263 loop_labels.iter().rev()
9264 {
9265 emit!(self, PseudoInstruction::Jump { delta: loop_block });
9266
9267 self.switch_to_block(if_cleanup_block);
9268 emit!(self, PseudoInstruction::Jump { delta: loop_block });
9269
9270 self.switch_to_block(after_block);
9271 if is_async {
9272 self.emit_end_async_for(end_async_for_target);
9273 } else {
9274 emit!(self, Instruction::EndFor);
9275 emit!(self, Instruction::PopIter);
9276 }
9277 }
9278
9279 if total_stack_items > 0 {
9281 emit!(self, PseudoInstruction::PopBlock);
9282 self.pop_fblock(FBlockType::TryExcept);
9283
9284 emit!(self, PseudoInstruction::Jump { delta: end_block });
9286
9287 self.switch_to_block(cleanup_block);
9289 emit!(self, Instruction::Swap { i: 2 });
9291 emit!(self, Instruction::PopTop); emit!(
9295 self,
9296 Instruction::Swap {
9297 i: u32::try_from(total_stack_items + 1).unwrap()
9298 }
9299 );
9300 for name in pushed_locals.iter().rev() {
9301 let var_num = self.varname(name)?;
9302 emit!(self, Instruction::StoreFast { var_num });
9303 }
9304 emit!(self, Instruction::Reraise { depth: 0 });
9306
9307 self.switch_to_block(end_block);
9309 }
9310
9311 if total_stack_items > 0 {
9313 emit!(
9314 self,
9315 Instruction::Swap {
9316 i: u32::try_from(total_stack_items + 1).unwrap()
9317 }
9318 );
9319 }
9320
9321 for name in pushed_locals.iter().rev() {
9323 let var_num = self.varname(name)?;
9324 emit!(self, Instruction::StoreFast { var_num });
9325 }
9326
9327 let current_table = self.symbol_table_stack.last_mut().expect("no symbol table");
9329 for (name, original_sym) in temp_symbols {
9330 current_table.symbols.insert(name, original_sym);
9331 }
9332
9333 Ok(())
9334 }
9335
9336 fn compile_future_features(&mut self, features: &[ast::Alias]) -> Result<(), CodegenError> {
9337 if let DoneWithFuture::Yes = self.done_with_future_stmts {
9338 return Err(self.error(CodegenErrorType::InvalidFuturePlacement));
9339 }
9340 self.done_with_future_stmts = DoneWithFuture::DoneWithDoc;
9341 for feature in features {
9342 match feature.name.as_str() {
9343 "nested_scopes" | "generators" | "division" | "absolute_import"
9345 | "with_statement" | "print_function" | "unicode_literals" | "generator_stop" => {}
9346 "annotations" => self.future_annotations = true,
9347 other => {
9348 return Err(
9349 self.error(CodegenErrorType::InvalidFutureFeature(other.to_owned()))
9350 );
9351 }
9352 }
9353 }
9354 Ok(())
9355 }
9356
9357 fn _emit<I: Into<AnyInstruction>>(&mut self, instr: I, arg: OpArg, target: BlockIdx) {
9359 if self.do_not_emit_bytecode > 0 {
9360 return;
9361 }
9362 let range = self.current_source_range;
9363 let source = self.source_file.to_source_code();
9364 let location = source.source_location(range.start(), PositionEncoding::Utf8);
9365 let end_location = source.source_location(range.end(), PositionEncoding::Utf8);
9366 let except_handler = None;
9367 self.current_block().instructions.push(ir::InstructionInfo {
9368 instr: instr.into(),
9369 arg,
9370 target,
9371 location,
9372 end_location,
9373 except_handler,
9374 lineno_override: None,
9375 cache_entries: 0,
9376 });
9377 }
9378
9379 fn set_no_location(&mut self) {
9382 if let Some(last) = self.current_block().instructions.last_mut() {
9383 last.lineno_override = Some(-1);
9384 }
9385 }
9386
9387 fn emit_no_arg<I: Into<AnyInstruction>>(&mut self, ins: I) {
9388 self._emit(ins, OpArg::NULL, BlockIdx::NULL)
9389 }
9390
9391 fn emit_arg<A: OpArgType, T: EmitArg<A>, I: Into<AnyInstruction>>(
9392 &mut self,
9393 arg: T,
9394 f: impl FnOnce(OpArgMarker<A>) -> I,
9395 ) {
9396 let (op, arg, target) = arg.emit(f);
9397 self._emit(op, arg, target)
9398 }
9399
9400 fn compile_string_value(&self, string: &ast::ExprStringLiteral) -> Wtf8Buf {
9404 let value = string.value.to_str();
9405 if value.contains(char::REPLACEMENT_CHARACTER) {
9406 string
9408 .value
9409 .iter()
9410 .map(|lit| {
9411 let source = self.source_file.slice(lit.range);
9412 crate::string_parser::parse_string_literal(source, lit.flags.into())
9413 })
9414 .collect()
9415 } else {
9416 value.into()
9417 }
9418 }
9419
9420 fn compile_fstring_literal_value(
9421 &self,
9422 string: &ast::InterpolatedStringLiteralElement,
9423 flags: ast::FStringFlags,
9424 ) -> Wtf8Buf {
9425 if string.value.contains(char::REPLACEMENT_CHARACTER) {
9426 let source = self.source_file.slice(string.range);
9427 crate::string_parser::parse_fstring_literal_element(source.into(), flags.into()).into()
9428 } else {
9429 string.value.to_string().into()
9430 }
9431 }
9432
9433 fn compile_fstring_part_literal_value(&self, string: &ast::StringLiteral) -> Wtf8Buf {
9434 if string.value.contains(char::REPLACEMENT_CHARACTER) {
9435 let source = self.source_file.slice(string.range);
9436 crate::string_parser::parse_string_literal(source, string.flags.into()).into()
9437 } else {
9438 string.value.to_string().into()
9439 }
9440 }
9441
9442 fn arg_constant(&mut self, constant: ConstantData) -> oparg::ConstIdx {
9443 let info = self.current_code_info();
9444 info.metadata.consts.insert_full(constant).0.to_u32().into()
9445 }
9446
9447 fn try_fold_constant_collection(
9450 &mut self,
9451 elts: &[ast::Expr],
9452 ) -> CompileResult<Option<ConstantData>> {
9453 let mut constants = Vec::with_capacity(elts.len());
9454 for elt in elts {
9455 let Some(constant) = self.try_fold_constant_expr(elt)? else {
9456 return Ok(None);
9457 };
9458 constants.push(constant);
9459 }
9460 Ok(Some(ConstantData::Tuple {
9461 elements: constants,
9462 }))
9463 }
9464
9465 fn try_fold_constant_expr(&mut self, expr: &ast::Expr) -> CompileResult<Option<ConstantData>> {
9466 Ok(Some(match expr {
9467 ast::Expr::NumberLiteral(num) => match &num.value {
9468 ast::Number::Int(int) => ConstantData::Integer {
9469 value: ruff_int_to_bigint(int).map_err(|e| self.error(e))?,
9470 },
9471 ast::Number::Float(f) => ConstantData::Float { value: *f },
9472 ast::Number::Complex { real, imag } => ConstantData::Complex {
9473 value: Complex::new(*real, *imag),
9474 },
9475 },
9476 ast::Expr::StringLiteral(s) => ConstantData::Str {
9477 value: self.compile_string_value(s),
9478 },
9479 ast::Expr::BytesLiteral(b) => ConstantData::Bytes {
9480 value: b.value.bytes().collect(),
9481 },
9482 ast::Expr::BooleanLiteral(b) => ConstantData::Boolean { value: b.value },
9483 ast::Expr::NoneLiteral(_) => ConstantData::None,
9484 ast::Expr::EllipsisLiteral(_) => ConstantData::Ellipsis,
9485 ast::Expr::Tuple(ast::ExprTuple { elts, .. }) => {
9486 let mut elements = Vec::with_capacity(elts.len());
9487 for elt in elts {
9488 let Some(constant) = self.try_fold_constant_expr(elt)? else {
9489 return Ok(None);
9490 };
9491 elements.push(constant);
9492 }
9493 ConstantData::Tuple { elements }
9494 }
9495 _ => return Ok(None),
9496 }))
9497 }
9498
9499 fn emit_load_const(&mut self, constant: ConstantData) {
9500 let idx = self.arg_constant(constant);
9501 self.emit_arg(idx, |consti| Instruction::LoadConst { consti })
9502 }
9503
9504 fn try_fold_constant_slice(
9506 &mut self,
9507 lower: Option<&ast::Expr>,
9508 upper: Option<&ast::Expr>,
9509 step: Option<&ast::Expr>,
9510 ) -> CompileResult<bool> {
9511 let to_const = |expr: Option<&ast::Expr>, this: &mut Self| -> CompileResult<_> {
9512 match expr {
9513 None => Ok(Some(ConstantData::None)),
9514 Some(expr) => this.try_fold_constant_expr(expr),
9515 }
9516 };
9517
9518 let (Some(start), Some(stop), Some(step_val)) = (
9519 to_const(lower, self)?,
9520 to_const(upper, self)?,
9521 to_const(step, self)?,
9522 ) else {
9523 return Ok(false);
9524 };
9525
9526 self.emit_load_const(ConstantData::Slice {
9527 elements: Box::new([start, stop, step_val]),
9528 });
9529 Ok(true)
9530 }
9531
9532 fn emit_return_const(&mut self, constant: ConstantData) {
9533 self.emit_load_const(constant);
9534 emit!(self, Instruction::ReturnValue)
9535 }
9536
9537 fn emit_end_async_for(&mut self, send_target: BlockIdx) {
9538 self._emit(Instruction::EndAsyncFor, OpArg::NULL, send_target);
9539 }
9540
9541 fn emit_load_attr(&mut self, name_idx: u32) {
9544 let encoded = LoadAttr::new(name_idx, false);
9545 self.emit_arg(encoded, |namei| Instruction::LoadAttr { namei })
9546 }
9547
9548 fn emit_load_attr_method(&mut self, name_idx: u32) {
9551 let encoded = LoadAttr::new(name_idx, true);
9552 self.emit_arg(encoded, |namei| Instruction::LoadAttr { namei })
9553 }
9554
9555 fn emit_load_global(&mut self, name_idx: u32, push_null: bool) {
9558 let encoded = (name_idx << 1) | u32::from(push_null);
9559 self.emit_arg(encoded, |namei| Instruction::LoadGlobal { namei });
9560 }
9561
9562 fn emit_load_super_attr(&mut self, name_idx: u32) {
9565 let encoded = LoadSuperAttr::new(name_idx, false, true);
9566 self.emit_arg(encoded, |namei| Instruction::LoadSuperAttr { namei })
9567 }
9568
9569 fn emit_load_super_method(&mut self, name_idx: u32) {
9572 let encoded = LoadSuperAttr::new(name_idx, true, true);
9573 self.emit_arg(encoded, |namei| Instruction::LoadSuperAttr { namei })
9574 }
9575
9576 fn emit_load_zero_super_attr(&mut self, name_idx: u32) {
9579 let encoded = LoadSuperAttr::new(name_idx, false, false);
9580 self.emit_arg(encoded, |namei| Instruction::LoadSuperAttr { namei })
9581 }
9582
9583 fn emit_load_zero_super_method(&mut self, name_idx: u32) {
9586 let encoded = LoadSuperAttr::new(name_idx, true, false);
9587 self.emit_arg(encoded, |namei| Instruction::LoadSuperAttr { namei })
9588 }
9589
9590 fn emit_return_value(&mut self) {
9591 emit!(self, Instruction::ReturnValue)
9592 }
9593
9594 fn current_code_info(&mut self) -> &mut ir::CodeInfo {
9595 self.code_stack.last_mut().expect("no code on stack")
9596 }
9597
9598 fn expr_constant(expr: &ast::Expr) -> Option<bool> {
9603 match expr {
9604 ast::Expr::BooleanLiteral(ast::ExprBooleanLiteral { value, .. }) => Some(*value),
9605 ast::Expr::NoneLiteral(_) => Some(false),
9606 ast::Expr::EllipsisLiteral(_) => Some(true),
9607 ast::Expr::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => match value {
9608 ast::Number::Int(i) => {
9609 let n: i64 = i.as_i64().unwrap_or(1);
9610 Some(n != 0)
9611 }
9612 ast::Number::Float(f) => Some(*f != 0.0),
9613 ast::Number::Complex { real, imag, .. } => Some(*real != 0.0 || *imag != 0.0),
9614 },
9615 ast::Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
9616 Some(!value.to_str().is_empty())
9617 }
9618 ast::Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => {
9619 Some(value.bytes().next().is_some())
9620 }
9621 ast::Expr::Tuple(ast::ExprTuple { elts, .. }) => {
9622 if elts.is_empty() {
9623 Some(false)
9624 } else {
9625 None }
9627 }
9628 _ => None,
9629 }
9630 }
9631
9632 fn emit_nop(&mut self) {
9633 emit!(self, Instruction::Nop);
9634 }
9635
9636 fn enter_conditional_block(&mut self) {
9639 self.current_code_info().in_conditional_block += 1;
9640 }
9641
9642 fn leave_conditional_block(&mut self) {
9644 let code_info = self.current_code_info();
9645 debug_assert!(code_info.in_conditional_block > 0);
9646 code_info.in_conditional_block -= 1;
9647 }
9648
9649 fn compile_break_continue(
9653 &mut self,
9654 range: ruff_text_size::TextRange,
9655 is_break: bool,
9656 ) -> CompileResult<()> {
9657 if self.do_not_emit_bytecode > 0 {
9658 let code = self.current_code_info();
9660 let mut found_loop = false;
9661 for i in (0..code.fblock.len()).rev() {
9662 match code.fblock[i].fb_type {
9663 FBlockType::WhileLoop | FBlockType::ForLoop => {
9664 found_loop = true;
9665 break;
9666 }
9667 FBlockType::ExceptionGroupHandler => {
9668 return Err(self.error_ranged(
9669 CodegenErrorType::BreakContinueReturnInExceptStar,
9670 range,
9671 ));
9672 }
9673 _ => {}
9674 }
9675 }
9676 if !found_loop {
9677 if is_break {
9678 return Err(self.error_ranged(CodegenErrorType::InvalidBreak, range));
9679 } else {
9680 return Err(self.error_ranged(CodegenErrorType::InvalidContinue, range));
9681 }
9682 }
9683 return Ok(());
9684 }
9685
9686 let code = self.current_code_info();
9693 let mut loop_idx = None;
9694 let mut is_for_loop = false;
9695
9696 for i in (0..code.fblock.len()).rev() {
9697 match code.fblock[i].fb_type {
9698 FBlockType::WhileLoop => {
9699 loop_idx = Some(i);
9700 is_for_loop = false;
9701 break;
9702 }
9703 FBlockType::ForLoop => {
9704 loop_idx = Some(i);
9705 is_for_loop = true;
9706 break;
9707 }
9708 FBlockType::ExceptionGroupHandler => {
9709 return Err(
9710 self.error_ranged(CodegenErrorType::BreakContinueReturnInExceptStar, range)
9711 );
9712 }
9713 _ => {}
9714 }
9715 }
9716
9717 let Some(loop_idx) = loop_idx else {
9718 if is_break {
9719 return Err(self.error_ranged(CodegenErrorType::InvalidBreak, range));
9720 } else {
9721 return Err(self.error_ranged(CodegenErrorType::InvalidContinue, range));
9722 }
9723 };
9724
9725 let loop_block = code.fblock[loop_idx].fb_block;
9726 let exit_block = code.fblock[loop_idx].fb_exit;
9727
9728 #[derive(Clone)]
9730 enum UnwindAction {
9731 With {
9732 is_async: bool,
9733 },
9734 HandlerCleanup {
9735 name: Option<String>,
9736 },
9737 TryExcept,
9738 FinallyTry {
9739 body: Vec<ruff_python_ast::Stmt>,
9740 fblock_idx: usize,
9741 },
9742 FinallyEnd,
9743 PopValue, }
9745 let mut unwind_actions = Vec::new();
9746
9747 {
9748 let code = self.current_code_info();
9749 for i in (loop_idx + 1..code.fblock.len()).rev() {
9750 match code.fblock[i].fb_type {
9751 FBlockType::With => {
9752 unwind_actions.push(UnwindAction::With { is_async: false });
9753 }
9754 FBlockType::AsyncWith => {
9755 unwind_actions.push(UnwindAction::With { is_async: true });
9756 }
9757 FBlockType::HandlerCleanup => {
9758 let name = match &code.fblock[i].fb_datum {
9759 FBlockDatum::ExceptionName(name) => Some(name.clone()),
9760 _ => None,
9761 };
9762 unwind_actions.push(UnwindAction::HandlerCleanup { name });
9763 }
9764 FBlockType::TryExcept => {
9765 unwind_actions.push(UnwindAction::TryExcept);
9766 }
9767 FBlockType::FinallyTry => {
9768 if let FBlockDatum::FinallyBody(ref body) = code.fblock[i].fb_datum {
9770 unwind_actions.push(UnwindAction::FinallyTry {
9771 body: body.clone(),
9772 fblock_idx: i,
9773 });
9774 }
9775 }
9776 FBlockType::FinallyEnd => {
9777 unwind_actions.push(UnwindAction::FinallyEnd);
9779 }
9780 FBlockType::PopValue => {
9781 unwind_actions.push(UnwindAction::PopValue);
9783 }
9784 _ => {}
9785 }
9786 }
9787 }
9788
9789 for action in unwind_actions {
9791 match action {
9792 UnwindAction::With { is_async } => {
9793 emit!(self, PseudoInstruction::PopBlock);
9795 self.emit_load_const(ConstantData::None);
9796 self.emit_load_const(ConstantData::None);
9797 self.emit_load_const(ConstantData::None);
9798 emit!(self, Instruction::Call { argc: 3 });
9799
9800 if is_async {
9801 emit!(self, Instruction::GetAwaitable { r#where: 2 });
9802 self.emit_load_const(ConstantData::None);
9803 let _ = self.compile_yield_from_sequence(true)?;
9804 }
9805
9806 emit!(self, Instruction::PopTop);
9807 }
9808 UnwindAction::HandlerCleanup { ref name } => {
9809 if name.is_some() {
9811 emit!(self, PseudoInstruction::PopBlock);
9813 }
9814 emit!(self, PseudoInstruction::PopBlock);
9816 emit!(self, Instruction::PopExcept);
9817 if let Some(name) = name {
9818 self.emit_load_const(ConstantData::None);
9819 self.store_name(name)?;
9820 self.compile_name(name, NameUsage::Delete)?;
9821 }
9822 }
9823 UnwindAction::TryExcept => {
9824 emit!(self, PseudoInstruction::PopBlock);
9826 }
9827 UnwindAction::FinallyTry { body, fblock_idx } => {
9828 emit!(self, PseudoInstruction::PopBlock);
9830
9831 let code = self.current_code_info();
9835 let saved_fblock = code.fblock.remove(fblock_idx);
9836
9837 self.compile_statements(&body)?;
9838
9839 let code = self.current_code_info();
9842 code.fblock.insert(fblock_idx, saved_fblock);
9843 }
9844 UnwindAction::FinallyEnd => {
9845 emit!(self, Instruction::PopTop); emit!(self, PseudoInstruction::PopBlock);
9848 emit!(self, Instruction::PopExcept);
9849 }
9850 UnwindAction::PopValue => {
9851 emit!(self, Instruction::PopTop);
9853 }
9854 }
9855 }
9856
9857 if is_break && is_for_loop {
9859 emit!(self, Instruction::PopIter);
9860 }
9861
9862 let target = if is_break { exit_block } else { loop_block };
9864 emit!(self, PseudoInstruction::Jump { delta: target });
9865
9866 Ok(())
9867 }
9868
9869 fn current_block(&mut self) -> &mut ir::Block {
9870 let info = self.current_code_info();
9871 &mut info.blocks[info.current_block]
9872 }
9873
9874 fn new_block(&mut self) -> BlockIdx {
9875 let code = self.current_code_info();
9876 let idx = BlockIdx::new(code.blocks.len().to_u32());
9877 code.blocks.push(ir::Block::default());
9878 idx
9879 }
9880
9881 fn switch_to_block(&mut self, block: BlockIdx) {
9882 let code = self.current_code_info();
9883 let prev = code.current_block;
9884 assert_ne!(prev, block, "recursive switching {prev:?} -> {block:?}");
9885 assert_eq!(
9886 code.blocks[block].next,
9887 BlockIdx::NULL,
9888 "switching {prev:?} -> {block:?} to completed block"
9889 );
9890 let prev_block = &mut code.blocks[prev.idx()];
9891 assert_eq!(
9892 u32::from(prev_block.next),
9893 u32::MAX,
9894 "switching {prev:?} -> {block:?} from block that's already got a next"
9895 );
9896 prev_block.next = block;
9897 code.current_block = block;
9898 }
9899
9900 const fn set_source_range(&mut self, range: TextRange) {
9901 self.current_source_range = range;
9902 }
9903
9904 fn get_source_line_number(&mut self) -> OneIndexed {
9905 self.source_file
9906 .to_source_code()
9907 .line_index(self.current_source_range.start())
9908 }
9909
9910 fn mark_generator(&mut self) {
9911 self.current_code_info().flags |= bytecode::CodeFlags::GENERATOR
9912 }
9913
9914 fn contains_await(expression: &ast::Expr) -> bool {
9924 use ast::visitor::Visitor;
9925
9926 #[derive(Default)]
9927 struct AwaitVisitor {
9928 found: bool,
9929 }
9930
9931 impl ast::visitor::Visitor<'_> for AwaitVisitor {
9932 fn visit_expr(&mut self, expr: &ast::Expr) {
9933 if self.found {
9934 return;
9935 }
9936
9937 match expr {
9938 ast::Expr::Await(_) => self.found = true,
9939 _ => ast::visitor::walk_expr(self, expr),
9945 }
9946 }
9947 }
9948
9949 let mut visitor = AwaitVisitor::default();
9950 visitor.visit_expr(expression);
9951 visitor.found
9952 }
9953
9954 fn generators_contain_await(generators: &[ast::Comprehension]) -> bool {
9957 for (i, generator) in generators.iter().enumerate() {
9958 if i > 0 && Self::contains_await(&generator.iter) {
9960 return true;
9961 }
9962 for if_expr in &generator.ifs {
9964 if Self::contains_await(if_expr) {
9965 return true;
9966 }
9967 }
9968 }
9969 false
9970 }
9971
9972 fn compile_expr_fstring(&mut self, fstring: &ast::ExprFString) -> CompileResult<()> {
9973 let fstring = &fstring.value;
9974 let mut element_count = 0;
9975 let mut pending_literal = None;
9976 for part in fstring {
9977 self.compile_fstring_part_into(part, &mut pending_literal, &mut element_count)?;
9978 }
9979 self.finish_fstring(pending_literal, element_count)
9980 }
9981
9982 fn compile_fstring_part_into(
9983 &mut self,
9984 part: &ast::FStringPart,
9985 pending_literal: &mut Option<Wtf8Buf>,
9986 element_count: &mut u32,
9987 ) -> CompileResult<()> {
9988 match part {
9989 ast::FStringPart::Literal(string) => {
9990 let value = self.compile_fstring_part_literal_value(string);
9991 if let Some(pending) = pending_literal.as_mut() {
9992 pending.push_wtf8(value.as_ref());
9993 } else {
9994 *pending_literal = Some(value);
9995 }
9996 Ok(())
9997 }
9998 ast::FStringPart::FString(fstring) => self.compile_fstring_elements_into(
9999 fstring.flags,
10000 &fstring.elements,
10001 pending_literal,
10002 element_count,
10003 ),
10004 }
10005 }
10006
10007 fn finish_fstring(
10008 &mut self,
10009 mut pending_literal: Option<Wtf8Buf>,
10010 mut element_count: u32,
10011 ) -> CompileResult<()> {
10012 let keep_empty = element_count == 0;
10013 self.emit_pending_fstring_literal(&mut pending_literal, &mut element_count, keep_empty);
10014
10015 if element_count == 0 {
10016 self.emit_load_const(ConstantData::Str {
10017 value: Wtf8Buf::new(),
10018 });
10019 } else if element_count > 1 {
10020 emit!(
10021 self,
10022 Instruction::BuildString {
10023 count: element_count
10024 }
10025 );
10026 }
10027
10028 Ok(())
10029 }
10030
10031 fn emit_pending_fstring_literal(
10032 &mut self,
10033 pending_literal: &mut Option<Wtf8Buf>,
10034 element_count: &mut u32,
10035 keep_empty: bool,
10036 ) {
10037 let Some(value) = pending_literal.take() else {
10038 return;
10039 };
10040
10041 if value.is_empty() && (!keep_empty || *element_count > 0) {
10045 return;
10046 }
10047
10048 self.emit_load_const(ConstantData::Str { value });
10049 *element_count += 1;
10050 }
10051
10052 fn try_optimize_format_str(
10056 &mut self,
10057 format_str: &str,
10058 args: &[ast::Expr],
10059 range: ruff_text_size::TextRange,
10060 ) -> CompileResult<bool> {
10061 let Some(segments) = Self::parse_percent_format(format_str) else {
10063 return Ok(false);
10064 };
10065
10066 let spec_count = segments.iter().filter(|s| s.conversion.is_some()).count();
10068 if spec_count != args.len() {
10069 return Ok(false);
10070 }
10071
10072 self.set_source_range(range);
10073
10074 if spec_count == 0 {
10076 let folded: String = segments.iter().map(|s| s.literal.as_str()).collect();
10077 self.emit_load_const(ConstantData::Str {
10078 value: folded.into(),
10079 });
10080 return Ok(true);
10081 }
10082
10083 let mut part_count: u32 = 0;
10085 let mut arg_idx = 0;
10086
10087 for seg in &segments {
10088 if !seg.literal.is_empty() {
10089 self.emit_load_const(ConstantData::Str {
10090 value: seg.literal.clone().into(),
10091 });
10092 part_count += 1;
10093 }
10094 if let Some(conv) = seg.conversion {
10095 self.compile_expression(&args[arg_idx])?;
10096 self.set_source_range(range);
10097 emit!(self, Instruction::ConvertValue { oparg: conv });
10098 emit!(self, Instruction::FormatSimple);
10099 part_count += 1;
10100 arg_idx += 1;
10101 }
10102 }
10103
10104 if part_count == 0 {
10105 self.emit_load_const(ConstantData::Str {
10106 value: String::new().into(),
10107 });
10108 } else if part_count > 1 {
10109 emit!(self, Instruction::BuildString { count: part_count });
10110 }
10111
10112 Ok(true)
10113 }
10114
10115 fn parse_percent_format(format_str: &str) -> Option<Vec<FormatSegment>> {
10118 let mut segments = Vec::new();
10119 let mut chars = format_str.chars().peekable();
10120 let mut current_literal = String::new();
10121
10122 while let Some(ch) = chars.next() {
10123 if ch == '%' {
10124 match chars.peek() {
10125 Some('%') => {
10126 chars.next();
10127 current_literal.push('%');
10128 }
10129 Some('s') => {
10130 chars.next();
10131 segments.push(FormatSegment {
10132 literal: core::mem::take(&mut current_literal),
10133 conversion: Some(oparg::ConvertValueOparg::Str),
10134 });
10135 }
10136 Some('r') => {
10137 chars.next();
10138 segments.push(FormatSegment {
10139 literal: core::mem::take(&mut current_literal),
10140 conversion: Some(oparg::ConvertValueOparg::Repr),
10141 });
10142 }
10143 Some('a') => {
10144 chars.next();
10145 segments.push(FormatSegment {
10146 literal: core::mem::take(&mut current_literal),
10147 conversion: Some(oparg::ConvertValueOparg::Ascii),
10148 });
10149 }
10150 _ => {
10151 return None;
10153 }
10154 }
10155 } else {
10156 current_literal.push(ch);
10157 }
10158 }
10159
10160 if !current_literal.is_empty() {
10162 segments.push(FormatSegment {
10163 literal: current_literal,
10164 conversion: None,
10165 });
10166 }
10167
10168 Some(segments)
10169 }
10170
10171 fn compile_fstring_elements(
10172 &mut self,
10173 flags: ast::FStringFlags,
10174 fstring_elements: &ast::InterpolatedStringElements,
10175 ) -> CompileResult<()> {
10176 let mut element_count = 0;
10177 let mut pending_literal: Option<Wtf8Buf> = None;
10178 self.compile_fstring_elements_into(
10179 flags,
10180 fstring_elements,
10181 &mut pending_literal,
10182 &mut element_count,
10183 )?;
10184 self.finish_fstring(pending_literal, element_count)
10185 }
10186
10187 fn compile_fstring_elements_into(
10188 &mut self,
10189 flags: ast::FStringFlags,
10190 fstring_elements: &ast::InterpolatedStringElements,
10191 pending_literal: &mut Option<Wtf8Buf>,
10192 element_count: &mut u32,
10193 ) -> CompileResult<()> {
10194 for element in fstring_elements {
10195 match element {
10196 ast::InterpolatedStringElement::Literal(string) => {
10197 let value = self.compile_fstring_literal_value(string, flags);
10198 if let Some(pending) = pending_literal.as_mut() {
10199 pending.push_wtf8(value.as_ref());
10200 } else {
10201 *pending_literal = Some(value);
10202 }
10203 }
10204 ast::InterpolatedStringElement::Interpolation(fstring_expr) => {
10205 let mut conversion = match fstring_expr.conversion {
10206 ast::ConversionFlag::None => ConvertValueOparg::None,
10207 ast::ConversionFlag::Str => ConvertValueOparg::Str,
10208 ast::ConversionFlag::Repr => ConvertValueOparg::Repr,
10209 ast::ConversionFlag::Ascii => ConvertValueOparg::Ascii,
10210 };
10211
10212 if let Some(ast::DebugText { leading, trailing }) = &fstring_expr.debug_text {
10213 let range = fstring_expr.expression.range();
10214 let source = self.source_file.slice(range);
10215 let text = [
10216 strip_fstring_debug_comments(leading).as_str(),
10217 source,
10218 strip_fstring_debug_comments(trailing).as_str(),
10219 ]
10220 .concat();
10221
10222 let text: Wtf8Buf = text.into();
10223 pending_literal
10224 .get_or_insert_with(Wtf8Buf::new)
10225 .push_wtf8(text.as_ref());
10226
10227 if matches!(
10230 (conversion, &fstring_expr.format_spec),
10231 (ConvertValueOparg::None, None)
10232 ) {
10233 conversion = ConvertValueOparg::Repr;
10234 }
10235 }
10236
10237 self.emit_pending_fstring_literal(pending_literal, element_count, false);
10238
10239 self.compile_expression(&fstring_expr.expression)?;
10240
10241 match conversion {
10242 ConvertValueOparg::None => {}
10243 ConvertValueOparg::Str
10244 | ConvertValueOparg::Repr
10245 | ConvertValueOparg::Ascii => {
10246 emit!(self, Instruction::ConvertValue { oparg: conversion })
10247 }
10248 }
10249
10250 match &fstring_expr.format_spec {
10251 Some(format_spec) => {
10252 self.compile_fstring_elements(flags, &format_spec.elements)?;
10253
10254 emit!(self, Instruction::FormatWithSpec);
10255 }
10256 None => {
10257 emit!(self, Instruction::FormatSimple);
10258 }
10259 }
10260
10261 *element_count += 1;
10262 }
10263 }
10264 }
10265
10266 Ok(())
10267 }
10268
10269 fn compile_expr_tstring(&mut self, expr_tstring: &ast::ExprTString) -> CompileResult<()> {
10270 let tstring_value = &expr_tstring.value;
10273
10274 let mut all_strings: Vec<Wtf8Buf> = Vec::new();
10276 let mut current_string = Wtf8Buf::new();
10277 let mut interp_count: u32 = 0;
10278
10279 for tstring in tstring_value.iter() {
10280 self.compile_tstring_into(
10281 tstring,
10282 &mut all_strings,
10283 &mut current_string,
10284 &mut interp_count,
10285 )?;
10286 }
10287
10288 all_strings.push(core::mem::take(&mut current_string));
10290
10291 emit!(
10296 self,
10297 Instruction::BuildTuple {
10298 count: interp_count
10299 }
10300 );
10301
10302 let string_count: u32 = all_strings
10304 .len()
10305 .try_into()
10306 .expect("t-string string count overflowed");
10307 for s in &all_strings {
10308 self.emit_load_const(ConstantData::Str { value: s.clone() });
10309 }
10310
10311 emit!(
10313 self,
10314 Instruction::BuildTuple {
10315 count: string_count
10316 }
10317 );
10318
10319 emit!(self, Instruction::Swap { i: 2 });
10321
10322 emit!(self, Instruction::BuildTemplate);
10324
10325 Ok(())
10326 }
10327
10328 fn compile_tstring_into(
10329 &mut self,
10330 tstring: &ast::TString,
10331 strings: &mut Vec<Wtf8Buf>,
10332 current_string: &mut Wtf8Buf,
10333 interp_count: &mut u32,
10334 ) -> CompileResult<()> {
10335 for element in &tstring.elements {
10336 match element {
10337 ast::InterpolatedStringElement::Literal(lit) => {
10338 current_string.push_str(&lit.value);
10340 }
10341 ast::InterpolatedStringElement::Interpolation(interp) => {
10342 strings.push(core::mem::take(current_string));
10344
10345 self.compile_expression(&interp.expression)?;
10347
10348 let expr_range = interp.expression.range();
10351 let expr_source = if interp.range.start() < expr_range.start()
10352 && interp.range.end() >= expr_range.end()
10353 {
10354 let after_brace = interp.range.start() + TextSize::new(1);
10355 self.source_file
10356 .slice(TextRange::new(after_brace, expr_range.end()))
10357 } else {
10358 self.source_file.slice(expr_range)
10360 };
10361 self.emit_load_const(ConstantData::Str {
10362 value: expr_source.to_string().into(),
10363 });
10364
10365 let conversion: u32 = match interp.conversion {
10367 ast::ConversionFlag::None => 0,
10368 ast::ConversionFlag::Str => 1,
10369 ast::ConversionFlag::Repr => 2,
10370 ast::ConversionFlag::Ascii => 3,
10371 };
10372
10373 let has_format_spec = interp.format_spec.is_some();
10375 if let Some(format_spec) = &interp.format_spec {
10376 self.compile_fstring_elements(
10379 ast::FStringFlags::empty(),
10380 &format_spec.elements,
10381 )?;
10382 }
10383
10384 let format = (conversion << 2) | u32::from(has_format_spec);
10387 emit!(self, Instruction::BuildInterpolation { format });
10388
10389 *interp_count += 1;
10390 }
10391 }
10392 }
10393
10394 Ok(())
10395 }
10396}
10397
10398trait EmitArg<Arg: OpArgType> {
10399 fn emit<I: Into<AnyInstruction>>(
10400 self,
10401 f: impl FnOnce(OpArgMarker<Arg>) -> I,
10402 ) -> (AnyInstruction, OpArg, BlockIdx);
10403}
10404
10405impl<T: OpArgType> EmitArg<T> for T {
10406 fn emit<I: Into<AnyInstruction>>(
10407 self,
10408 f: impl FnOnce(OpArgMarker<T>) -> I,
10409 ) -> (AnyInstruction, OpArg, BlockIdx) {
10410 let (marker, arg) = OpArgMarker::new(self);
10411 (f(marker).into(), arg, BlockIdx::NULL)
10412 }
10413}
10414
10415impl EmitArg<bytecode::Label> for BlockIdx {
10416 fn emit<I: Into<AnyInstruction>>(
10417 self,
10418 f: impl FnOnce(OpArgMarker<bytecode::Label>) -> I,
10419 ) -> (AnyInstruction, OpArg, BlockIdx) {
10420 (f(OpArgMarker::marker()).into(), OpArg::NULL, self)
10421 }
10422}
10423
10424fn clean_doc(doc: &str) -> String {
10429 let doc = expandtabs(doc, 8);
10430 let margin = doc
10433 .split('\n')
10434 .skip(1) .filter(|line| line.chars().any(|c| c != ' ')) .map(|line| line.chars().take_while(|c| *c == ' ').count())
10437 .min()
10438 .unwrap_or(0);
10439
10440 let mut cleaned = String::with_capacity(doc.len());
10441 if let Some(first_line) = doc.split('\n').next() {
10443 let trimmed = first_line.trim_start();
10444 if trimmed.len() == first_line.len() && margin == 0 {
10446 return doc.to_owned();
10447 }
10448 cleaned.push_str(trimmed);
10449 }
10450 for line in doc.split('\n').skip(1) {
10452 cleaned.push('\n');
10453 let skip = line.chars().take(margin).take_while(|c| *c == ' ').count();
10454 cleaned.push_str(&line[skip..]);
10455 }
10456
10457 cleaned
10458}
10459
10460fn expandtabs(input: &str, tab_size: usize) -> String {
10462 let tab_stop = tab_size;
10463 let mut expanded_str = String::with_capacity(input.len());
10464 let mut tab_size = tab_stop;
10465 let mut col_count = 0usize;
10466 for ch in input.chars() {
10467 match ch {
10468 '\t' => {
10469 let num_spaces = tab_size - col_count;
10470 col_count += num_spaces;
10471 let expand = " ".repeat(num_spaces);
10472 expanded_str.push_str(&expand);
10473 }
10474 '\r' | '\n' => {
10475 expanded_str.push(ch);
10476 col_count = 0;
10477 tab_size = 0;
10478 }
10479 _ => {
10480 expanded_str.push(ch);
10481 col_count += 1;
10482 }
10483 }
10484 if col_count >= tab_size {
10485 tab_size += tab_stop;
10486 }
10487 }
10488 expanded_str
10489}
10490
10491fn split_doc<'a>(body: &'a [ast::Stmt], opts: &CompileOpts) -> (Option<String>, &'a [ast::Stmt]) {
10492 if let Some((ast::Stmt::Expr(expr), body_rest)) = body.split_first() {
10493 let doc_comment = match &*expr.value {
10494 ast::Expr::StringLiteral(value) => Some(&value.value),
10495 ast::Expr::FString(_) => None,
10497 _ => None,
10498 };
10499 if let Some(doc) = doc_comment {
10500 return if opts.optimize < 2 {
10501 (Some(clean_doc(doc.to_str())), body_rest)
10502 } else {
10503 (None, body_rest)
10504 };
10505 }
10506 }
10507 (None, body)
10508}
10509
10510pub fn ruff_int_to_bigint(int: &ast::Int) -> Result<BigInt, CodegenErrorType> {
10511 if let Some(small) = int.as_u64() {
10512 Ok(BigInt::from(small))
10513 } else {
10514 parse_big_integer(int)
10515 }
10516}
10517
10518fn parse_big_integer(int: &ast::Int) -> Result<BigInt, CodegenErrorType> {
10521 let s = format!("{int}");
10524 let mut s = s.as_str();
10525 let radix = match s.get(0..2) {
10527 Some("0b" | "0B") => {
10528 s = s.get(2..).unwrap_or(s);
10529 2
10530 }
10531 Some("0o" | "0O") => {
10532 s = s.get(2..).unwrap_or(s);
10533 8
10534 }
10535 Some("0x" | "0X") => {
10536 s = s.get(2..).unwrap_or(s);
10537 16
10538 }
10539 _ => 10,
10540 };
10541
10542 BigInt::from_str_radix(s, radix).map_err(|e| {
10543 CodegenErrorType::SyntaxError(format!(
10544 "unparsed integer literal (radix {radix}): {s} ({e})"
10545 ))
10546 })
10547}
10548
10549trait ToU32 {
10551 fn to_u32(self) -> u32;
10552}
10553
10554impl ToU32 for usize {
10555 fn to_u32(self) -> u32 {
10556 self.try_into().unwrap()
10557 }
10558}
10559
10560fn strip_fstring_debug_comments(text: &str) -> String {
10564 let mut result = String::with_capacity(text.len());
10565 let mut in_comment = false;
10566 for ch in text.chars() {
10567 if in_comment {
10568 if ch == '\n' {
10569 in_comment = false;
10570 result.push(ch);
10571 }
10572 } else if ch == '#' {
10573 in_comment = true;
10574 } else {
10575 result.push(ch);
10576 }
10577 }
10578 result
10579}
10580
10581#[cfg(test)]
10582mod ruff_tests {
10583 use super::*;
10584 use ast::name::Name;
10585
10586 #[test]
10588 fn test_fstring_contains_await() {
10589 let range = TextRange::default();
10590 let flags = ast::FStringFlags::empty();
10591
10592 let expr_x = ast::Expr::Name(ast::ExprName {
10594 node_index: ast::AtomicNodeIndex::NONE,
10595 range,
10596 id: Name::new("x"),
10597 ctx: ast::ExprContext::Load,
10598 });
10599 let not_present = &ast::Expr::FString(ast::ExprFString {
10600 node_index: ast::AtomicNodeIndex::NONE,
10601 range,
10602 value: ast::FStringValue::single(ast::FString {
10603 node_index: ast::AtomicNodeIndex::NONE,
10604 range,
10605 elements: vec![ast::InterpolatedStringElement::Interpolation(
10606 ast::InterpolatedElement {
10607 node_index: ast::AtomicNodeIndex::NONE,
10608 range,
10609 expression: Box::new(expr_x),
10610 debug_text: None,
10611 conversion: ast::ConversionFlag::None,
10612 format_spec: None,
10613 },
10614 )]
10615 .into(),
10616 flags,
10617 }),
10618 });
10619 assert!(!Compiler::contains_await(not_present));
10620
10621 let expr_await_x = ast::Expr::Await(ast::ExprAwait {
10623 node_index: ast::AtomicNodeIndex::NONE,
10624 range,
10625 value: Box::new(ast::Expr::Name(ast::ExprName {
10626 node_index: ast::AtomicNodeIndex::NONE,
10627 range,
10628 id: Name::new("x"),
10629 ctx: ast::ExprContext::Load,
10630 })),
10631 });
10632 let present = &ast::Expr::FString(ast::ExprFString {
10633 node_index: ast::AtomicNodeIndex::NONE,
10634 range,
10635 value: ast::FStringValue::single(ast::FString {
10636 node_index: ast::AtomicNodeIndex::NONE,
10637 range,
10638 elements: vec![ast::InterpolatedStringElement::Interpolation(
10639 ast::InterpolatedElement {
10640 node_index: ast::AtomicNodeIndex::NONE,
10641 range,
10642 expression: Box::new(expr_await_x),
10643 debug_text: None,
10644 conversion: ast::ConversionFlag::None,
10645 format_spec: None,
10646 },
10647 )]
10648 .into(),
10649 flags,
10650 }),
10651 });
10652 assert!(Compiler::contains_await(present));
10653
10654 let expr_x = ast::Expr::Name(ast::ExprName {
10656 node_index: ast::AtomicNodeIndex::NONE,
10657 range,
10658 id: Name::new("x"),
10659 ctx: ast::ExprContext::Load,
10660 });
10661 let expr_await_y = ast::Expr::Await(ast::ExprAwait {
10662 node_index: ast::AtomicNodeIndex::NONE,
10663 range,
10664 value: Box::new(ast::Expr::Name(ast::ExprName {
10665 node_index: ast::AtomicNodeIndex::NONE,
10666 range,
10667 id: Name::new("y"),
10668 ctx: ast::ExprContext::Load,
10669 })),
10670 });
10671 let present = &ast::Expr::FString(ast::ExprFString {
10672 node_index: ast::AtomicNodeIndex::NONE,
10673 range,
10674 value: ast::FStringValue::single(ast::FString {
10675 node_index: ast::AtomicNodeIndex::NONE,
10676 range,
10677 elements: vec![ast::InterpolatedStringElement::Interpolation(
10678 ast::InterpolatedElement {
10679 node_index: ast::AtomicNodeIndex::NONE,
10680 range,
10681 expression: Box::new(expr_x),
10682 debug_text: None,
10683 conversion: ast::ConversionFlag::None,
10684 format_spec: Some(Box::new(ast::InterpolatedStringFormatSpec {
10685 node_index: ast::AtomicNodeIndex::NONE,
10686 range,
10687 elements: vec![ast::InterpolatedStringElement::Interpolation(
10688 ast::InterpolatedElement {
10689 node_index: ast::AtomicNodeIndex::NONE,
10690 range,
10691 expression: Box::new(expr_await_y),
10692 debug_text: None,
10693 conversion: ast::ConversionFlag::None,
10694 format_spec: None,
10695 },
10696 )]
10697 .into(),
10698 })),
10699 },
10700 )]
10701 .into(),
10702 flags,
10703 }),
10704 });
10705 assert!(Compiler::contains_await(present));
10706 }
10707}
10708
10709#[cfg(test)]
10710mod tests {
10711 use super::*;
10712 use rustpython_compiler_core::{SourceFileBuilder, bytecode::OpArg};
10713
10714 fn assert_scope_exit_locations(code: &CodeObject) {
10715 for (instr, (location, _)) in code.instructions.iter().zip(code.locations.iter()) {
10716 if matches!(
10717 instr.op,
10718 Instruction::ReturnValue
10719 | Instruction::RaiseVarargs { .. }
10720 | Instruction::Reraise { .. }
10721 ) {
10722 assert!(
10723 location.line.get() > 0,
10724 "scope-exit instruction {instr:?} is missing a line number"
10725 );
10726 }
10727 }
10728 for constant in code.constants.iter() {
10729 if let ConstantData::Code { code } = constant {
10730 assert_scope_exit_locations(code);
10731 }
10732 }
10733 }
10734
10735 fn compile_exec(source: &str) -> CodeObject {
10736 let opts = CompileOpts::default();
10737 compile_exec_with_options(source, opts)
10738 }
10739
10740 fn compile_exec_optimized(source: &str) -> CodeObject {
10741 let opts = CompileOpts {
10742 optimize: 1,
10743 ..CompileOpts::default()
10744 };
10745 compile_exec_with_options(source, opts)
10746 }
10747
10748 fn compile_exec_with_options(source: &str, opts: CompileOpts) -> CodeObject {
10749 let source_file = SourceFileBuilder::new("source_path", source).finish();
10750 let parsed = ruff_python_parser::parse(
10751 source_file.source_text(),
10752 ruff_python_parser::Mode::Module.into(),
10753 )
10754 .unwrap();
10755 let ast = parsed.into_syntax();
10756 let ast = match ast {
10757 ruff_python_ast::Mod::Module(stmts) => stmts,
10758 _ => unreachable!(),
10759 };
10760 let symbol_table = SymbolTable::scan_program(&ast, source_file.clone())
10761 .map_err(|e| e.into_codegen_error(source_file.name().to_owned()))
10762 .unwrap();
10763 let mut compiler = Compiler::new(opts, source_file, "<module>".to_owned());
10764 compiler.compile_program(&ast, symbol_table).unwrap();
10765 compiler.exit_scope()
10766 }
10767
10768 fn find_code<'a>(code: &'a CodeObject, name: &str) -> Option<&'a CodeObject> {
10769 if code.obj_name == name {
10770 return Some(code);
10771 }
10772 code.constants.iter().find_map(|constant| {
10773 if let ConstantData::Code { code } = constant {
10774 find_code(code, name)
10775 } else {
10776 None
10777 }
10778 })
10779 }
10780
10781 fn has_common_constant(code: &CodeObject, expected: bytecode::CommonConstant) -> bool {
10782 code.instructions.iter().any(|unit| match unit.op {
10783 Instruction::LoadCommonConstant { idx } => {
10784 idx.get(OpArg::new(u32::from(u8::from(unit.arg)))) == expected
10785 }
10786 _ => false,
10787 })
10788 }
10789
10790 fn has_intrinsic_1(code: &CodeObject, expected: IntrinsicFunction1) -> bool {
10791 code.instructions.iter().any(|unit| match unit.op {
10792 Instruction::CallIntrinsic1 { func } => {
10793 func.get(OpArg::new(u32::from(u8::from(unit.arg)))) == expected
10794 }
10795 _ => false,
10796 })
10797 }
10798
10799 macro_rules! assert_dis_snapshot {
10800 ($value:expr) => {
10801 insta::assert_snapshot!(
10802 insta::internals::AutoName,
10803 $value.display_expand_code_objects().to_string(),
10804 stringify!($value)
10805 )
10806 };
10807 }
10808
10809 #[test]
10810 fn test_if_ors() {
10811 assert_dis_snapshot!(compile_exec(
10812 "\
10813if True or False or False:
10814 pass
10815"
10816 ));
10817 }
10818
10819 #[test]
10820 fn test_if_ands() {
10821 assert_dis_snapshot!(compile_exec(
10822 "\
10823if True and False and False:
10824 pass
10825"
10826 ));
10827 }
10828
10829 #[test]
10830 fn test_if_mixed() {
10831 assert_dis_snapshot!(compile_exec(
10832 "\
10833if (True and False) or (False and True):
10834 pass
10835"
10836 ));
10837 }
10838
10839 #[test]
10840 fn test_nested_bool_op() {
10841 assert_dis_snapshot!(compile_exec(
10842 "\
10843x = Test() and False or False
10844"
10845 ));
10846 }
10847
10848 #[test]
10849 fn test_const_bool_not_op() {
10850 assert_dis_snapshot!(compile_exec_optimized(
10851 "\
10852x = not True
10853"
10854 ));
10855 }
10856
10857 #[test]
10858 fn test_nested_double_async_with() {
10859 assert_dis_snapshot!(compile_exec(
10860 "\
10861async def test():
10862 for stop_exc in (StopIteration('spam'), StopAsyncIteration('ham')):
10863 with self.subTest(type=type(stop_exc)):
10864 try:
10865 async with egg():
10866 raise stop_exc
10867 except Exception as ex:
10868 self.assertIs(ex, stop_exc)
10869 else:
10870 self.fail(f'{stop_exc} was suppressed')
10871"
10872 ));
10873 }
10874
10875 #[test]
10876 fn test_scope_exit_instructions_keep_line_numbers() {
10877 let code = compile_exec(
10878 "\
10879async def test():
10880 for stop_exc in (StopIteration('spam'), StopAsyncIteration('ham')):
10881 with self.subTest(type=type(stop_exc)):
10882 try:
10883 async with egg():
10884 raise stop_exc
10885 except Exception as ex:
10886 self.assertIs(ex, stop_exc)
10887 else:
10888 self.fail(f'{stop_exc} was suppressed')
10889",
10890 );
10891 assert_scope_exit_locations(&code);
10892 }
10893
10894 #[test]
10895 fn test_attribute_ex_call_uses_plain_load_attr() {
10896 let code = compile_exec(
10897 "\
10898def f(cls, args, kwargs):
10899 cls.__new__(cls, *args)
10900 cls.__new__(cls, *args, **kwargs)
10901",
10902 );
10903 let f = find_code(&code, "f").expect("missing function code");
10904
10905 let ex_call_count = f
10906 .instructions
10907 .iter()
10908 .filter(|unit| matches!(unit.op, Instruction::CallFunctionEx))
10909 .count();
10910 let load_attr_count = f
10911 .instructions
10912 .iter()
10913 .filter(|unit| matches!(unit.op, Instruction::LoadAttr { .. }))
10914 .count();
10915
10916 assert_eq!(ex_call_count, 2);
10917 assert_eq!(load_attr_count, 2);
10918
10919 for unit in f.instructions.iter() {
10920 if let Instruction::LoadAttr { namei } = unit.op {
10921 let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
10922 assert!(
10923 !load_attr.is_method(),
10924 "CALL_FUNCTION_EX should use plain LOAD_ATTR"
10925 );
10926 }
10927 }
10928 }
10929
10930 #[test]
10931 fn test_simple_attribute_call_keeps_method_load() {
10932 let code = compile_exec(
10933 "\
10934def f(obj, arg):
10935 return obj.method(arg)
10936",
10937 );
10938 let f = find_code(&code, "f").expect("missing function code");
10939 let load_attr = f
10940 .instructions
10941 .iter()
10942 .find_map(|unit| match unit.op {
10943 Instruction::LoadAttr { namei } => {
10944 Some(namei.get(OpArg::new(u32::from(u8::from(unit.arg)))))
10945 }
10946 _ => None,
10947 })
10948 .expect("missing LOAD_ATTR");
10949
10950 assert!(
10951 load_attr.is_method(),
10952 "simple method calls should stay optimized"
10953 );
10954 }
10955
10956 #[test]
10957 fn test_builtin_any_genexpr_call_is_optimized() {
10958 let code = compile_exec(
10959 "\
10960def f(xs):
10961 return any(x for x in xs)
10962",
10963 );
10964 let f = find_code(&code, "f").expect("missing function code");
10965
10966 assert!(has_common_constant(f, bytecode::CommonConstant::BuiltinAny));
10967 assert!(
10968 f.instructions
10969 .iter()
10970 .any(|unit| matches!(unit.op, Instruction::PopJumpIfTrue { .. }))
10971 );
10972 assert!(
10973 f.instructions
10974 .iter()
10975 .any(|unit| matches!(unit.op, Instruction::NotTaken))
10976 );
10977 assert_eq!(
10978 f.instructions
10979 .iter()
10980 .filter(|unit| matches!(unit.op, Instruction::PushNull))
10981 .count(),
10982 1,
10983 "fallback call path should remain for shadowed any()"
10984 );
10985 }
10986
10987 #[test]
10988 fn test_builtin_tuple_list_set_genexpr_calls_are_optimized() {
10989 let code = compile_exec(
10990 "\
10991def tuple_f(xs):
10992 return tuple(x for x in xs)
10993
10994def list_f(xs):
10995 return list(x for x in xs)
10996
10997def set_f(xs):
10998 return set(x for x in xs)
10999",
11000 );
11001
11002 let tuple_f = find_code(&code, "tuple_f").expect("missing tuple_f code");
11003 assert!(has_common_constant(
11004 tuple_f,
11005 bytecode::CommonConstant::BuiltinTuple
11006 ));
11007 assert!(has_intrinsic_1(tuple_f, IntrinsicFunction1::ListToTuple));
11008 let tuple_list_append = tuple_f
11009 .instructions
11010 .iter()
11011 .find_map(|unit| match unit.op {
11012 Instruction::ListAppend { .. } => Some(u32::from(u8::from(unit.arg))),
11013 _ => None,
11014 })
11015 .expect("tuple(genexpr) fast path should emit LIST_APPEND");
11016 assert_eq!(tuple_list_append, 2);
11017
11018 let list_f = find_code(&code, "list_f").expect("missing list_f code");
11019 assert!(has_common_constant(
11020 list_f,
11021 bytecode::CommonConstant::BuiltinList
11022 ));
11023 assert!(
11024 list_f
11025 .instructions
11026 .iter()
11027 .any(|unit| matches!(unit.op, Instruction::ListAppend { .. }))
11028 );
11029
11030 let set_f = find_code(&code, "set_f").expect("missing set_f code");
11031 assert!(has_common_constant(
11032 set_f,
11033 bytecode::CommonConstant::BuiltinSet
11034 ));
11035 assert!(
11036 set_f
11037 .instructions
11038 .iter()
11039 .any(|unit| matches!(unit.op, Instruction::SetAdd { .. }))
11040 );
11041 }
11042
11043 #[test]
11044 fn test_module_store_uses_store_global_when_nested_scope_declares_global() {
11045 let code = compile_exec(
11046 "\
11047_address_fmt_re = None
11048
11049class C:
11050 def f(self):
11051 global _address_fmt_re
11052 if _address_fmt_re is None:
11053 _address_fmt_re = 1
11054",
11055 );
11056
11057 assert!(code.instructions.iter().any(|unit| match unit.op {
11058 Instruction::StoreGlobal { namei } => {
11059 let idx = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
11060 code.names[usize::try_from(idx).unwrap()].as_str() == "_address_fmt_re"
11061 }
11062 _ => false,
11063 }));
11064 }
11065
11066 #[test]
11067 fn test_conditional_return_epilogue_is_duplicated() {
11068 let code = compile_exec(
11069 "\
11070def f(base, cls, state):
11071 if base is object:
11072 obj = object.__new__(cls)
11073 else:
11074 obj = base.__new__(cls, state)
11075 return obj
11076",
11077 );
11078 let f = find_code(&code, "f").expect("missing function code");
11079 let return_count = f
11080 .instructions
11081 .iter()
11082 .filter(|unit| matches!(unit.op, Instruction::ReturnValue))
11083 .count();
11084
11085 assert_eq!(return_count, 2);
11086 }
11087
11088 #[test]
11089 fn test_assert_without_message_raises_class_directly() {
11090 let code = compile_exec(
11091 "\
11092def f(x):
11093 assert x
11094",
11095 );
11096 let f = find_code(&code, "f").expect("missing function code");
11097 let call_count = f
11098 .instructions
11099 .iter()
11100 .filter(|unit| matches!(unit.op, Instruction::Call { .. }))
11101 .count();
11102 let push_null_count = f
11103 .instructions
11104 .iter()
11105 .filter(|unit| matches!(unit.op, Instruction::PushNull))
11106 .count();
11107
11108 assert_eq!(call_count, 0);
11109 assert_eq!(push_null_count, 0);
11110 }
11111
11112 #[test]
11113 fn test_chained_compare_jump_uses_single_cleanup_copy() {
11114 let code = compile_exec(
11115 "\
11116def f(code):
11117 if not 1 <= code <= 2147483647:
11118 raise ValueError('x')
11119",
11120 );
11121 let f = find_code(&code, "f").expect("missing function code");
11122 let copy_count = f
11123 .instructions
11124 .iter()
11125 .filter(|unit| matches!(unit.op, Instruction::Copy { .. }))
11126 .count();
11127 let pop_top_count = f
11128 .instructions
11129 .iter()
11130 .filter(|unit| matches!(unit.op, Instruction::PopTop))
11131 .count();
11132
11133 assert_eq!(copy_count, 1);
11134 assert_eq!(pop_top_count, 1);
11135 }
11136
11137 #[test]
11138 fn test_constant_slice_folding_handles_string_and_bigint_bounds() {
11139 let code = compile_exec(
11140 "\
11141def f(obj):
11142 return obj['a':123456789012345678901234567890]
11143",
11144 );
11145 let f = find_code(&code, "f").expect("missing function code");
11146 let slice = f
11147 .constants
11148 .iter()
11149 .find_map(|constant| match constant {
11150 ConstantData::Slice { elements } => Some(elements),
11151 _ => None,
11152 })
11153 .expect("missing folded slice constant");
11154
11155 assert!(matches!(slice[0], ConstantData::Str { .. }));
11156 assert!(matches!(slice[1], ConstantData::Integer { .. }));
11157 assert!(matches!(slice[2], ConstantData::None));
11158 }
11159
11160 #[test]
11161 fn test_exception_cleanup_jump_to_return_is_inlined() {
11162 let code = compile_exec(
11163 "\
11164def f(names, cls):
11165 try:
11166 cls.attr = names
11167 except:
11168 pass
11169 return names
11170",
11171 );
11172 let f = find_code(&code, "f").expect("missing function code");
11173 let return_count = f
11174 .instructions
11175 .iter()
11176 .filter(|unit| matches!(unit.op, Instruction::ReturnValue))
11177 .count();
11178
11179 assert_eq!(return_count, 2);
11180 }
11181
11182 #[test]
11183 fn test_fstring_adjacent_literals_are_merged() {
11184 let code = compile_exec(
11185 "\
11186def f(cls, proto):
11187 raise TypeError(
11188 f\"cannot pickle {cls.__name__!r} object: \"
11189 f\"a class that defines __slots__ without \"
11190 f\"defining __getstate__ cannot be pickled \"
11191 f\"with protocol {proto}\"
11192 )
11193",
11194 );
11195 let f = find_code(&code, "f").expect("missing function code");
11196 let string_consts = f
11197 .instructions
11198 .iter()
11199 .filter_map(|unit| match unit.op {
11200 Instruction::LoadConst { consti } => {
11201 Some(&f.constants[consti.get(OpArg::new(u32::from(u8::from(unit.arg))))])
11202 }
11203 _ => None,
11204 })
11205 .filter_map(|constant| match constant {
11206 ConstantData::Str { value } => Some(value.to_string()),
11207 _ => None,
11208 })
11209 .collect::<Vec<_>>();
11210
11211 assert!(
11212 string_consts.iter().any(|value| {
11213 value
11214 == " object: a class that defines __slots__ without defining __getstate__ cannot be pickled with protocol "
11215 }),
11216 "expected merged trailing f-string literal, got {string_consts:?}"
11217 );
11218 assert!(
11219 !string_consts.iter().any(|value| value == " object: "),
11220 "did not expect split trailing literal, got {string_consts:?}"
11221 );
11222 }
11223
11224 #[test]
11225 fn test_literal_only_fstring_statement_is_optimized_away() {
11226 let code = compile_exec(
11227 "\
11228def f():
11229 f'''Not a docstring'''
11230",
11231 );
11232 let f = find_code(&code, "f").expect("missing function code");
11233
11234 assert!(
11235 !f.instructions
11236 .iter()
11237 .any(|unit| matches!(unit.op, Instruction::PopTop)),
11238 "literal-only f-string statement should be removed"
11239 );
11240 assert!(
11241 !f.constants.iter().any(|constant| matches!(
11242 constant,
11243 ConstantData::Str { value } if value.to_string() == "Not a docstring"
11244 )),
11245 "literal-only f-string should not survive in constants"
11246 );
11247 }
11248
11249 #[test]
11250 fn test_empty_fstring_literals_are_elided_around_interpolation() {
11251 let code = compile_exec(
11252 "\
11253def f(x):
11254 if '' f'{x}':
11255 return 1
11256 return 2
11257",
11258 );
11259 let f = find_code(&code, "f").expect("missing function code");
11260
11261 let empty_string_loads = f
11262 .instructions
11263 .iter()
11264 .filter_map(|unit| match unit.op {
11265 Instruction::LoadConst { consti } => {
11266 Some(&f.constants[consti.get(OpArg::new(u32::from(u8::from(unit.arg))))])
11267 }
11268 _ => None,
11269 })
11270 .filter(|constant| {
11271 matches!(
11272 constant,
11273 ConstantData::Str { value } if value.is_empty()
11274 )
11275 })
11276 .count();
11277 let build_string_count = f
11278 .instructions
11279 .iter()
11280 .filter(|unit| matches!(unit.op, Instruction::BuildString { .. }))
11281 .count();
11282
11283 assert_eq!(empty_string_loads, 0);
11284 assert_eq!(build_string_count, 0);
11285 }
11286
11287 #[test]
11288 fn test_large_power_is_not_constant_folded() {
11289 let code = compile_exec("x = 2**100\n");
11290
11291 assert!(code.instructions.iter().any(|unit| match unit.op {
11292 Instruction::BinaryOp { op } => {
11293 op.get(OpArg::new(u32::from(u8::from(unit.arg)))) == oparg::BinaryOperator::Power
11294 }
11295 _ => false,
11296 }));
11297 }
11298
11299 #[test]
11300 fn test_list_of_constant_tuples_uses_list_extend() {
11301 let code = compile_exec(
11302 "\
11303deprecated_cases = [('a', 'b'), ('c', 'd'), ('e', 'f'), ('g', 'h'), ('i', 'j')]
11304",
11305 );
11306
11307 assert!(
11308 code.instructions
11309 .iter()
11310 .any(|unit| matches!(unit.op, Instruction::ListExtend { .. })),
11311 "expected constant tuple list folding"
11312 );
11313 }
11314
11315 #[test]
11316 fn test_constant_list_iterable_uses_tuple() {
11317 let code = compile_exec(
11318 "\
11319def f():
11320 return {x: y for x, y in [(1, 2), ]}
11321",
11322 );
11323 let f = find_code(&code, "f").expect("missing function code");
11324
11325 assert!(
11326 !f.instructions
11327 .iter()
11328 .any(|unit| matches!(unit.op, Instruction::BuildList { .. })),
11329 "constant list iterable should avoid BUILD_LIST before GET_ITER"
11330 );
11331 assert!(f.constants.iter().any(|constant| matches!(
11332 constant,
11333 ConstantData::Tuple { elements }
11334 if matches!(
11335 elements.as_slice(),
11336 [ConstantData::Tuple { elements: inner }]
11337 if matches!(
11338 inner.as_slice(),
11339 [
11340 ConstantData::Integer { .. },
11341 ConstantData::Integer { .. }
11342 ]
11343 )
11344 )
11345 )));
11346 }
11347
11348 #[test]
11349 fn test_constant_set_iterable_keeps_runtime_set_build() {
11350 let code = compile_exec(
11351 "\
11352def f():
11353 return [x for x in {1, 2, 3}]
11354",
11355 );
11356 let f = find_code(&code, "f").expect("missing function code");
11357
11358 assert!(
11359 f.instructions
11360 .iter()
11361 .any(|unit| matches!(unit.op, Instruction::BuildSet { .. })),
11362 "constant set iterable should keep BUILD_SET before GET_ITER"
11363 );
11364 assert!(f.constants.iter().any(|constant| matches!(
11365 constant,
11366 ConstantData::Tuple { elements }
11367 if matches!(
11368 elements.as_slice(),
11369 [
11370 ConstantData::Integer { .. },
11371 ConstantData::Integer { .. },
11372 ConstantData::Integer { .. }
11373 ]
11374 )
11375 )));
11376 }
11377
11378 #[test]
11379 fn test_optimized_assert_preserves_nested_scope_order() {
11380 compile_exec_optimized(
11381 "\
11382class S:
11383 def f(self, sequence):
11384 _formats = [self._types_mapping[type(item)] for item in sequence]
11385 _list_len = len(_formats)
11386 assert sum(len(fmt) <= 8 for fmt in _formats) == _list_len
11387 _recreation_codes = [self._extract_recreation_code(item) for item in sequence]
11388",
11389 );
11390 }
11391
11392 #[test]
11393 fn test_optimized_assert_with_nested_scope_in_first_iter() {
11394 compile_exec_optimized(
11398 "\
11399def f(items):
11400 assert [x for x in (y for y in items)]
11401 return [x for x in items]
11402",
11403 );
11404 }
11405
11406 #[test]
11407 fn test_optimized_assert_with_lambda_defaults() {
11408 compile_exec_optimized(
11411 "\
11412def f(items):
11413 assert (lambda x=[i for i in items]: x)()
11414 return [x for x in items]
11415",
11416 );
11417 }
11418}