@@ -36,6 +36,51 @@ use rustpython_compiler_core::{
3636} ;
3737use rustpython_wtf8:: Wtf8Buf ;
3838
39+ /// Extension trait for `ast::Expr` to add constant checking methods
40+ trait ExprExt {
41+ /// Check if an expression is a constant literal
42+ fn is_constant ( & self ) -> bool ;
43+
44+ /// Check if a slice expression has all constant elements
45+ fn is_constant_slice ( & self ) -> bool ;
46+
47+ /// Check if we should use BINARY_SLICE/STORE_SLICE optimization
48+ fn should_use_slice_optimization ( & self ) -> bool ;
49+ }
50+
51+ impl ExprExt for ast:: Expr {
52+ fn is_constant ( & self ) -> bool {
53+ matches ! (
54+ self ,
55+ ast:: Expr :: NumberLiteral ( _)
56+ | ast:: Expr :: StringLiteral ( _)
57+ | ast:: Expr :: BytesLiteral ( _)
58+ | ast:: Expr :: NoneLiteral ( _)
59+ | ast:: Expr :: BooleanLiteral ( _)
60+ | ast:: Expr :: EllipsisLiteral ( _)
61+ )
62+ }
63+
64+ fn is_constant_slice ( & self ) -> bool {
65+ match self {
66+ ast:: Expr :: Slice ( s) => {
67+ let lower_const =
68+ s. lower . is_none ( ) || s. lower . as_deref ( ) . is_some_and ( |e| e. is_constant ( ) ) ;
69+ let upper_const =
70+ s. upper . is_none ( ) || s. upper . as_deref ( ) . is_some_and ( |e| e. is_constant ( ) ) ;
71+ let step_const =
72+ s. step . is_none ( ) || s. step . as_deref ( ) . is_some_and ( |e| e. is_constant ( ) ) ;
73+ lower_const && upper_const && step_const
74+ }
75+ _ => false ,
76+ }
77+ }
78+
79+ fn should_use_slice_optimization ( & self ) -> bool {
80+ !self . is_constant_slice ( ) && matches ! ( self , ast:: Expr :: Slice ( s) if s. step. is_none( ) )
81+ }
82+ }
83+
3984const MAXBLOCKS : usize = 20 ;
4085
4186#[ derive( Debug , Clone , Copy ) ]
@@ -425,39 +470,25 @@ impl Compiler {
425470 }
426471 }
427472
428- /// Check if the slice is a two-element slice (no step)
429- // = is_two_element_slice
430- const fn is_two_element_slice ( slice : & ast:: Expr ) -> bool {
431- matches ! ( slice, ast:: Expr :: Slice ( s) if s. step. is_none( ) )
432- }
433-
434- /// Compile a slice expression
435- // = compiler_slice
436- fn compile_slice ( & mut self , s : & ast:: ExprSlice ) -> CompileResult < BuildSliceArgCount > {
437- // Compile lower
473+ /// Compile just start and stop of a slice (for BINARY_SLICE/STORE_SLICE)
474+ // = codegen_slice_two_parts
475+ fn compile_slice_two_parts ( & mut self , s : & ast:: ExprSlice ) -> CompileResult < ( ) > {
476+ // Compile lower (or None)
438477 if let Some ( lower) = & s. lower {
439478 self . compile_expression ( lower) ?;
440479 } else {
441480 self . emit_load_const ( ConstantData :: None ) ;
442481 }
443482
444- // Compile upper
483+ // Compile upper (or None)
445484 if let Some ( upper) = & s. upper {
446485 self . compile_expression ( upper) ?;
447486 } else {
448487 self . emit_load_const ( ConstantData :: None ) ;
449488 }
450489
451- Ok ( match & s. step {
452- Some ( step) => {
453- // Compile step if present
454- self . compile_expression ( step) ?;
455- BuildSliceArgCount :: Three
456- }
457- None => BuildSliceArgCount :: Two ,
458- } )
490+ Ok ( ( ) )
459491 }
460-
461492 /// Compile a subscript expression
462493 // = compiler_subscript
463494 fn compile_subscript (
@@ -480,27 +511,20 @@ impl Compiler {
480511 // VISIT(c, expr, e->v.Subscript.value)
481512 self . compile_expression ( value) ?;
482513
483- // Handle two-element slice (for Load/Store, not Del)
484- if Self :: is_two_element_slice ( slice) && !matches ! ( ctx, ast:: ExprContext :: Del ) {
485- let argc = match slice {
486- ast:: Expr :: Slice ( s) => self . compile_slice ( s) ?,
514+ // Handle two-element non-constant slice with BINARY_SLICE/STORE_SLICE
515+ if slice. should_use_slice_optimization ( ) && !matches ! ( ctx, ast:: ExprContext :: Del ) {
516+ match slice {
517+ ast:: Expr :: Slice ( s) => self . compile_slice_two_parts ( s) ?,
487518 _ => unreachable ! (
488- "is_two_element_slice should only return true for ast::Expr::Slice"
519+ "should_use_slice_optimization should only return true for ast::Expr::Slice"
489520 ) ,
490521 } ;
491522 match ctx {
492523 ast:: ExprContext :: Load => {
493- emit ! ( self , Instruction :: BuildSlice { argc } ) ;
494- emit ! (
495- self ,
496- Instruction :: BinaryOp {
497- op: BinaryOperator :: Subscr
498- }
499- ) ;
524+ emit ! ( self , Instruction :: BinarySlice ) ;
500525 }
501526 ast:: ExprContext :: Store => {
502- emit ! ( self , Instruction :: BuildSlice { argc } ) ;
503- emit ! ( self , Instruction :: StoreSubscr ) ;
527+ emit ! ( self , Instruction :: StoreSlice ) ;
504528 }
505529 _ => unreachable ! ( ) ,
506530 }
@@ -1269,8 +1293,12 @@ impl Compiler {
12691293 emit ! ( self , Instruction :: PopJumpIfFalse { target: body_block } ) ;
12701294
12711295 // Raise NotImplementedError
1272- let not_implemented_error = self . name ( "NotImplementedError" ) ;
1273- emit ! ( self , Instruction :: LoadGlobal ( not_implemented_error) ) ;
1296+ emit ! (
1297+ self ,
1298+ Instruction :: LoadCommonConstant {
1299+ idx: bytecode:: CommonConstant :: NotImplementedError
1300+ }
1301+ ) ;
12741302 emit ! (
12751303 self ,
12761304 Instruction :: RaiseVarargs {
@@ -2345,8 +2373,12 @@ impl Compiler {
23452373 let after_block = self . new_block ( ) ;
23462374 self . compile_jump_if ( test, true , after_block) ?;
23472375
2348- let assertion_error = self . name ( "AssertionError" ) ;
2349- emit ! ( self , Instruction :: LoadGlobal ( assertion_error) ) ;
2376+ emit ! (
2377+ self ,
2378+ Instruction :: LoadCommonConstant {
2379+ idx: bytecode:: CommonConstant :: AssertionError
2380+ }
2381+ ) ;
23502382 emit ! ( self , Instruction :: PushNull ) ;
23512383 match msg {
23522384 Some ( e) => {
@@ -3326,11 +3358,9 @@ impl Compiler {
33263358 // ADDOP_I(c, loc, COPY, 1);
33273359 // ADDOP_JUMP(c, loc, POP_JUMP_IF_NONE, no_match);
33283360 emit ! ( self , Instruction :: Copy { index: 1 } ) ;
3329- self . emit_load_const ( ConstantData :: None ) ;
3330- emit ! ( self , Instruction :: IsOp ( bytecode:: Invert :: No ) ) ; // is None?
33313361 emit ! (
33323362 self ,
3333- Instruction :: PopJumpIfTrue {
3363+ Instruction :: PopJumpIfNone {
33343364 target: no_match_block
33353365 }
33363366 ) ;
@@ -3455,11 +3485,9 @@ impl Compiler {
34553485 // Stack: [prev_exc, result, result]
34563486
34573487 // POP_JUMP_IF_NOT_NONE reraise
3458- self . emit_load_const ( ConstantData :: None ) ;
3459- emit ! ( self , Instruction :: IsOp ( bytecode:: Invert :: Yes ) ) ; // is not None?
34603488 emit ! (
34613489 self ,
3462- Instruction :: PopJumpIfTrue {
3490+ Instruction :: PopJumpIfNotNone {
34633491 target: reraise_block
34643492 }
34653493 ) ;
0 commit comments