Patch 9.0.1134
Problem:    Comparing objects uses identity instead of equality.
Solution:   Compare the object values.
Files:      src/typval.c, src/proto/typval.pro, src/vim9.h, src/vim9instr.c,
            src/vim9expr.c, src/vim9execute.c, src/testdir/test_vim9_class.vim


*** ../vim-9.0.1133/src/typval.c        2022-12-25 19:31:29.517203739 +0000
--- src/typval.c        2023-01-02 20:31:36.217755171 +0000
***************
*** 1310,1315 ****
--- 1310,1333 ----
        }
        n1 = res;
      }
+     else if (tv1->v_type == VAR_CLASS || tv2->v_type == VAR_CLASS)
+     {
+       if (typval_compare_class(tv1, tv2, type, ic, &res) == FAIL)
+       {
+           clear_tv(tv1);
+           return FAIL;
+       }
+       n1 = res;
+     }
+     else if (tv1->v_type == VAR_OBJECT || tv2->v_type == VAR_OBJECT)
+     {
+       if (typval_compare_object(tv1, tv2, type, ic, &res) == FAIL)
+       {
+           clear_tv(tv1);
+           return FAIL;
+       }
+       n1 = res;
+     }
      else if (tv1->v_type == VAR_DICT || tv2->v_type == VAR_DICT)
      {
        if (typval_compare_dict(tv1, tv2, type, ic, &res) == FAIL)
***************
*** 1580,1585 ****
--- 1598,1674 ----
  }
  
  /*
+  * Compare "tv1" to "tv2" as classes according to "type".
+  * Put the result, false or true, in "res".
+  * Return FAIL and give an error message when the comparison can't be done.
+  */
+     int
+ typval_compare_class(
+       typval_T    *tv1,
+       typval_T    *tv2,
+       exprtype_T  type UNUSED,
+       int         ic UNUSED,
+       int         *res)
+ {
+     // TODO: use "type"
+     *res = tv1->vval.v_class == tv2->vval.v_class;
+     return OK;
+ }
+ 
+ /*
+  * Compare "tv1" to "tv2" as objects according to "type".
+  * Put the result, false or true, in "res".
+  * Return FAIL and give an error message when the comparison can't be done.
+  */
+     int
+ typval_compare_object(
+       typval_T    *tv1,
+       typval_T    *tv2,
+       exprtype_T  type,
+       int         ic,
+       int         *res)
+ {
+     int res_match = type == EXPR_EQUAL || type == EXPR_IS ? TRUE : FALSE;
+ 
+     if (tv1->vval.v_object == NULL && tv2->vval.v_object == NULL)
+     {
+       *res = res_match;
+       return OK;
+     }
+     if (tv1->vval.v_object == NULL || tv2->vval.v_object == NULL)
+     {
+       *res = !res_match;
+       return OK;
+     }
+ 
+     class_T *cl1 = tv1->vval.v_object->obj_class;
+     class_T *cl2 = tv2->vval.v_object->obj_class;
+     if (cl1 != cl2 || cl1 == NULL || cl2 == NULL)
+     {
+       *res = !res_match;
+       return OK;
+     }
+ 
+     object_T *obj1 = tv1->vval.v_object;
+     object_T *obj2 = tv2->vval.v_object;
+     if (type == EXPR_IS || type == EXPR_ISNOT)
+     {
+       *res = obj1 == obj2 ? res_match : !res_match;
+       return OK;
+     }
+ 
+     for (int i = 0; i < cl1->class_obj_member_count; ++i)
+       if (!tv_equal((typval_T *)(obj1 + 1) + i,
+                                (typval_T *)(obj2 + 1) + i, ic, TRUE))
+       {
+           *res = !res_match;
+           return OK;
+       }
+     *res = res_match;
+     return OK;
+ }
+ 
+ /*
   * Compare "tv1" to "tv2" as dictionaries according to "type" and "ic".
   * Put the result, false or true, in "res".
   * Return FAIL and give an error message when the comparison can't be done.
***************
*** 1920,1930 ****
            return tv1->vval.v_instr == tv2->vval.v_instr;
  
        case VAR_CLASS:
            return tv1->vval.v_class == tv2->vval.v_class;
  
        case VAR_OBJECT:
!           // TODO: compare values
!           return tv1->vval.v_object == tv2->vval.v_object;
  
        case VAR_PARTIAL:
            return tv1->vval.v_partial == tv2->vval.v_partial;
--- 2009,2020 ----
            return tv1->vval.v_instr == tv2->vval.v_instr;
  
        case VAR_CLASS:
+           // A class only exists once, equality is identity.
            return tv1->vval.v_class == tv2->vval.v_class;
  
        case VAR_OBJECT:
!           (void)typval_compare_object(tv1, tv2, EXPR_EQUAL, ic, &r);
!           return r;
  
        case VAR_PARTIAL:
            return tv1->vval.v_partial == tv2->vval.v_partial;
*** ../vim-9.0.1133/src/proto/typval.pro        2022-09-09 18:46:41.558660414 
+0100
--- src/proto/typval.pro        2023-01-02 19:20:44.936983380 +0000
***************
*** 63,68 ****
--- 63,70 ----
  int typval_compare_list(typval_T *tv1, typval_T *tv2, exprtype_T type, int 
ic, int *res);
  int typval_compare_null(typval_T *tv1, typval_T *tv2);
  int typval_compare_blob(typval_T *tv1, typval_T *tv2, exprtype_T type, int 
*res);
+ int typval_compare_class(typval_T *tv1, typval_T *tv2, exprtype_T type, int 
ic, int *res);
+ int typval_compare_object(typval_T *tv1, typval_T *tv2, exprtype_T type, int 
ic, int *res);
  int typval_compare_dict(typval_T *tv1, typval_T *tv2, exprtype_T type, int 
ic, int *res);
  int typval_compare_func(typval_T *tv1, typval_T *tv2, exprtype_T type, int 
ic, int *res);
  int typval_compare_string(typval_T *tv1, typval_T *tv2, exprtype_T type, int 
ic, int *res);
*** ../vim-9.0.1133/src/vim9.h  2022-12-18 21:42:49.010716927 +0000
--- src/vim9.h  2023-01-02 18:54:27.202079939 +0000
***************
*** 164,169 ****
--- 164,171 ----
      ISN_COMPAREDICT,
      ISN_COMPAREFUNC,
      ISN_COMPAREANY,
+     ISN_COMPARECLASS,
+     ISN_COMPAREOBJECT,
  
      // expression operations
      ISN_CONCAT,     // concatenate isn_arg.number strings
*** ../vim-9.0.1133/src/vim9instr.c     2022-12-30 10:36:30.029867662 +0000
--- src/vim9instr.c     2023-01-02 19:56:15.957983838 +0000
***************
*** 254,264 ****
   */
      int
  generate_add_instr(
!       cctx_T *cctx,
!       vartype_T vartype,
!       type_T *type1,
!       type_T *type2,
!       exprtype_T expr_type)
  {
      isn_T     *isn = generate_instr_drop(cctx,
                      vartype == VAR_NUMBER ? ISN_OPNR
--- 254,264 ----
   */
      int
  generate_add_instr(
!       cctx_T      *cctx,
!       vartype_T   vartype,
!       type_T      *type1,
!       type_T      *type2,
!       exprtype_T  expr_type)
  {
      isn_T     *isn = generate_instr_drop(cctx,
                      vartype == VAR_NUMBER ? ISN_OPNR
***************
*** 416,421 ****
--- 416,423 ----
            case VAR_LIST: isntype = ISN_COMPARELIST; break;
            case VAR_DICT: isntype = ISN_COMPAREDICT; break;
            case VAR_FUNC: isntype = ISN_COMPAREFUNC; break;
+           case VAR_CLASS: isntype = ISN_COMPARECLASS; break;
+           case VAR_OBJECT: isntype = ISN_COMPAREOBJECT; break;
            default: isntype = ISN_COMPAREANY; break;
        }
      }
***************
*** 455,460 ****
--- 457,469 ----
                exprtype == EXPR_IS ? "is" : "isnot" , vartype_name(vartype1));
        return ISN_DROP;
      }
+     if (!(exprtype == EXPR_IS || exprtype == EXPR_ISNOT
+               || exprtype == EXPR_EQUAL || exprtype == EXPR_NEQUAL)
+           && (isntype == ISN_COMPAREOBJECT || isntype == ISN_COMPARECLASS))
+     {
+       semsg(_(e_invalid_operation_for_str), vartype_name(vartype1));
+       return ISN_DROP;
+     }
      if (isntype == ISN_DROP
            || ((exprtype != EXPR_EQUAL && exprtype != EXPR_NEQUAL
                    && (vartype1 == VAR_BOOL || vartype1 == VAR_SPECIAL
***************
*** 2512,2523 ****
--- 2521,2534 ----
        case ISN_COMPAREANY:
        case ISN_COMPAREBLOB:
        case ISN_COMPAREBOOL:
+       case ISN_COMPARECLASS:
        case ISN_COMPAREDICT:
        case ISN_COMPAREFLOAT:
        case ISN_COMPAREFUNC:
        case ISN_COMPARELIST:
        case ISN_COMPARENR:
        case ISN_COMPARENULL:
+       case ISN_COMPAREOBJECT:
        case ISN_COMPARESPECIAL:
        case ISN_COMPARESTRING:
        case ISN_CONCAT:
*** ../vim-9.0.1133/src/vim9expr.c      2023-01-02 18:10:00.023271223 +0000
--- src/vim9expr.c      2023-01-02 20:25:15.893803016 +0000
***************
*** 273,279 ****
      class_T *cl = (class_T *)type->tt_member;
      if (*name_end == '(')
      {
!       // TODO
      }
      else if (type->tt_type == VAR_OBJECT)
      {
--- 273,280 ----
      class_T *cl = (class_T *)type->tt_member;
      if (*name_end == '(')
      {
!       // TODO: method or function call
!       emsg("compile_class_object_index(): object/class call not handled yet");
      }
      else if (type->tt_type == VAR_OBJECT)
      {
***************
*** 300,306 ****
      else
      {
        // TODO: class member
!       emsg("compile_class_object_index(): not handled");
      }
  
      return FAIL;
--- 301,307 ----
      else
      {
        // TODO: class member
!       emsg("compile_class_object_index(): class member not handled yet");
      }
  
      return FAIL;
*** ../vim-9.0.1133/src/vim9execute.c   2023-01-02 18:10:00.023271223 +0000
--- src/vim9execute.c   2023-01-02 19:04:20.013552171 +0000
***************
*** 4697,4702 ****
--- 4697,4704 ----
            case ISN_COMPAREFUNC:
            case ISN_COMPARESTRING:
            case ISN_COMPAREBLOB:
+           case ISN_COMPARECLASS:
+           case ISN_COMPAREOBJECT:
                {
                    typval_T    *tv1 = STACK_TV_BOT(-2);
                    typval_T    *tv2 = STACK_TV_BOT(-1);
***************
*** 4726,4735 ****
                        status = typval_compare_string(tv1, tv2,
                                                           exprtype, ic, &res);
                    }
!                   else
                    {
                        status = typval_compare_blob(tv1, tv2, exprtype, &res);
                    }
                    --ectx->ec_stack.ga_len;
                    clear_tv(tv1);
                    clear_tv(tv2);
--- 4728,4746 ----
                        status = typval_compare_string(tv1, tv2,
                                                           exprtype, ic, &res);
                    }
!                   else if (iptr->isn_type == ISN_COMPAREBLOB)
                    {
                        status = typval_compare_blob(tv1, tv2, exprtype, &res);
                    }
+                   else if (iptr->isn_type == ISN_COMPARECLASS)
+                   {
+                       status = typval_compare_class(tv1, tv2, exprtype, &res);
+                   }
+                   else // ISN_COMPAREOBJECT
+                   {
+                       status = typval_compare_object(tv1, tv2,
+                                                              exprtype, &res);
+                   }
                    --ectx->ec_stack.ga_len;
                    clear_tv(tv1);
                    clear_tv(tv2);
***************
*** 6807,6812 ****
--- 6818,6825 ----
            case ISN_COMPARELIST:
            case ISN_COMPAREDICT:
            case ISN_COMPAREFUNC:
+           case ISN_COMPARECLASS:
+           case ISN_COMPAREOBJECT:
            case ISN_COMPAREANY:
                   {
                       char *p;
***************
*** 6844,6849 ****
--- 6857,6865 ----
                           case ISN_COMPARELIST: type = "COMPARELIST"; break;
                           case ISN_COMPAREDICT: type = "COMPAREDICT"; break;
                           case ISN_COMPAREFUNC: type = "COMPAREFUNC"; break;
+                          case ISN_COMPARECLASS: type = "COMPARECLASS"; break;
+                          case ISN_COMPAREOBJECT:
+                                                type = "COMPAREOBJECT"; break;
                           case ISN_COMPAREANY: type = "COMPAREANY"; break;
                           default: type = "???"; break;
                       }
*** ../vim-9.0.1133/src/testdir/test_vim9_class.vim     2023-01-01 
19:53:26.586445815 +0000
--- src/testdir/test_vim9_class.vim     2023-01-02 20:27:57.825782691 +0000
***************
*** 367,372 ****
--- 367,416 ----
    v9.CheckScriptFailure(lines, 'E1041:')
  enddef
  
+ def Test_class_object_compare()
+   var class_lines =<< trim END
+       vim9script
+       class Item
+         this.nr = 0
+         this.name = 'xx'
+       endclass
+   END
+ 
+   # used at the script level and in a compiled function
+   var test_lines =<< trim END
+       var i1 = Item.new()
+       assert_equal(i1, i1)
+       assert_true(i1 is i1)
+       var i2 = Item.new()
+       assert_equal(i1, i2)
+       assert_false(i1 is i2)
+       var i3 = Item.new(0, 'xx')
+       assert_equal(i1, i3)
+ 
+       var io1 = Item.new(1, 'xx')
+       assert_notequal(i1, io1)
+       var io2 = Item.new(0, 'yy')
+       assert_notequal(i1, io2)
+   END
+ 
+   v9.CheckScriptSuccess(class_lines + test_lines)
+   # TODO: this does not work yet
+   #v9.CheckScriptSuccess(
+   #    class_lines + ['def Test()'] + test_lines + ['enddef', 'Test()'])
+ 
+   for op in ['>', '>=', '<', '<=', '=~', '!~']
+     var op_lines = [
+           'var i1 = Item.new()',
+           'var i2 = Item.new()',
+           'echo i1 ' .. op .. ' i2',
+           ]
+     v9.CheckScriptFailure(class_lines + op_lines, 'E1153: Invalid operation 
for object')
+     # TODO: this does not work yet
+     #v9.CheckScriptFailure(class_lines
+     #      + ['def Test()'] + op_lines + ['enddef', 'Test()'], 'E99:')
+   endfor
+ enddef
+ 
  def Test_class_member()
    # check access rules
    var lines =<< trim END
*** ../vim-9.0.1133/src/version.c       2023-01-02 18:10:00.027271224 +0000
--- src/version.c       2023-01-02 18:34:58.626644391 +0000
***************
*** 697,698 ****
--- 697,700 ----
  {   /* Add new patch number below this line */
+ /**/
+     1134,
  /**/

-- 
The chat program is in public domain.  This is not the GNU public license.
If it breaks then you get to keep both pieces.
                -- Copyright notice for the chat program

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20230102203252.B6DFA1C0AA3%40moolenaar.net.

Raspunde prin e-mail lui