@@ -608,6 +608,22 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
608608 Ok ( ( ) )
609609 } ,
610610 Insn :: Snapshot { state } => write ! ( f, "Snapshot {}" , state) ,
611+ Insn :: Defined { op_type, v, .. } => {
612+ // op_type (enum defined_type) printing logic from iseq.c.
613+ // Not sure why rb_iseq_defined_string() isn't exhaustive.
614+ use std:: borrow:: Cow ;
615+ let op_type = * op_type as u32 ;
616+ let op_type = if op_type == DEFINED_FUNC {
617+ Cow :: Borrowed ( "func" )
618+ } else if op_type == DEFINED_REF {
619+ Cow :: Borrowed ( "ref" )
620+ } else if op_type == DEFINED_CONST_FROM {
621+ Cow :: Borrowed ( "constant-from" )
622+ } else {
623+ String :: from_utf8_lossy ( unsafe { rb_iseq_defined_string ( op_type) . as_rstring_byte_slice ( ) . unwrap ( ) } )
624+ } ;
625+ write ! ( f, "Defined {op_type}, {v}" )
626+ }
611627 Insn :: DefinedIvar { self_val, id, .. } => write ! ( f, "DefinedIvar {self_val}, :{}" , id. contents_lossy( ) . into_owned( ) ) ,
612628 Insn :: GetIvar { self_val, id, .. } => write ! ( f, "GetIvar {self_val}, :{}" , id. contents_lossy( ) . into_owned( ) ) ,
613629 Insn :: SetIvar { self_val, id, val, .. } => write ! ( f, "SetIvar {self_val}, :{}, {val}" , id. contents_lossy( ) . into_owned( ) ) ,
@@ -2152,9 +2168,10 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
21522168 state. stack_push ( fun. push_insn ( block, Insn :: Const { val : Const :: Value ( VALUE :: fixnum_from_usize ( 1 ) ) } ) ) ;
21532169 }
21542170 YARVINSN_defined => {
2171+ // (rb_num_t op_type, VALUE obj, VALUE pushval)
21552172 let op_type = get_arg ( pc, 0 ) . as_usize ( ) ;
2156- let obj = get_arg ( pc, 0 ) ;
2157- let pushval = get_arg ( pc, 0 ) ;
2173+ let obj = get_arg ( pc, 1 ) ;
2174+ let pushval = get_arg ( pc, 2 ) ;
21582175 let v = state. stack_pop ( ) ?;
21592176 state. stack_push ( fun. push_insn ( block, Insn :: Defined { op_type, obj, pushval, v } ) ) ;
21602177 }
@@ -3007,6 +3024,25 @@ mod tests {
30073024 "# ] ] ) ;
30083025 }
30093026
3027+ #[ test]
3028+ fn defined ( ) {
3029+ eval ( "
3030+ def test = return defined?(SeaChange), defined?(favourite), defined?($ruby)
3031+ " ) ;
3032+ assert_method_hir_with_opcodes ( "test" , & [ YARVINSN_defined ] , expect ! [ [ r#"
3033+ fn test:
3034+ bb0():
3035+ v1:NilClassExact = Const Value(nil)
3036+ v2:BasicObject = Defined constant, v1
3037+ v3:BasicObject = PutSelf
3038+ v4:BasicObject = Defined func, v3
3039+ v5:NilClassExact = Const Value(nil)
3040+ v6:BasicObject = Defined global-variable, v5
3041+ v8:ArrayExact = NewArray v2, v4, v6
3042+ Return v8
3043+ "# ] ] ) ;
3044+ }
3045+
30103046 #[ test]
30113047 fn test_return_const ( ) {
30123048 eval ( "
0 commit comments