changeset 32414:385e847edfb7

Fix nargout -1 for classdefs subsrefs from VM (bug #64775) Support calling subsref with nargout -1 as binary and unary ops make nargout unknown, for classdef that might return cs-lists. * libinterp/parse-tree/pt-bytecode-vm.cc: Handle nargout -1 * libinterp/parse-tree/pt-bytecode-walk.cc: nargout -1 for some . and { subsrefs * libinterp/parse-tree/pt-bytecode-walk.h: New field used to track if nargout -1 could be needed with
author Petter T. <petter.vilhelm@gmail.com>
date Sun, 15 Oct 2023 16:50:47 +0200
parents ee5d0bded6d4
children b747729c6695
files libinterp/parse-tree/pt-bytecode-vm.cc libinterp/parse-tree/pt-bytecode-walk.cc libinterp/parse-tree/pt-bytecode-walk.h
diffstat 3 files changed, 54 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/parse-tree/pt-bytecode-vm.cc	Sat Oct 14 19:13:12 2023 +0200
+++ b/libinterp/parse-tree/pt-bytecode-vm.cc	Sun Oct 15 16:50:47 2023 +0200
@@ -5031,6 +5031,13 @@
 index_struct_call:
   {
     int nargout = arg0;
+    // TODO: Kludge alert. Mirror the behaviour in ov_classdef::subsref
+    // where under certain conditions a magic number nargout of -1 is
+    // expected to  maybe return a cs-list. "-1" in this context 
+    // does not have the same meaning as in the VM, where it means
+    // a varargout with only one return symbol 'varargout'.
+    if (nargout == 255)
+      nargout = -1;
     bool has_slot = *ip++;
     int slot = POP_CODE_USHORT ();
 
@@ -5217,6 +5224,13 @@
     CATCH_EXIT_EXCEPTION
 
     STACK_DESTROY (1);
+  // TODO: Kludge alert. Mirror the behaviour in ov_classdef::subsref
+  // where under certain conditions a magic number nargout of -1 is
+  // expected to  maybe return a cs-list. "-1" in this context 
+  // does not have the same meaning as in the VM, where it means
+  // a varargout with only one return symbol 'varargout'.
+    if (nargout == -1)
+      nargout = 1;
     EXPAND_CSLIST_PUSH_N_OVL_ELEMENTS_TO_STACK (retval, nargout);
   }
   DISPATCH ();
--- a/libinterp/parse-tree/pt-bytecode-walk.cc	Sat Oct 14 19:13:12 2023 +0200
+++ b/libinterp/parse-tree/pt-bytecode-walk.cc	Sun Oct 15 16:50:47 2023 +0200
@@ -1397,6 +1397,7 @@
 bytecode_walker::
 visit_postfix_expression (tree_postfix_expression& expr)
 {
+  m_unknown_nargout++;
   INC_DEPTH();
 
   tree_expression *e = expr.operand ();
@@ -1524,12 +1525,14 @@
   maybe_emit_bind_ans_and_disp (expr);
 
   DEC_DEPTH();
+  m_unknown_nargout--;
 }
 
 void
 bytecode_walker::
 visit_prefix_expression (tree_prefix_expression& expr)
 {
+  m_unknown_nargout++;
   INC_DEPTH();
 
   tree_expression *e = expr.operand ();
@@ -1657,6 +1660,7 @@
   maybe_emit_bind_ans_and_disp (expr);
 
   DEC_DEPTH();
+  m_unknown_nargout--;
 }
 
 void
@@ -1773,6 +1777,7 @@
   // do fused for a matrix, like M'*A etc.
   INC_DEPTH();
   PUSH_NARGOUT (1);
+  m_unknown_nargout++;
 
   tree_expression *op1 = expr.clhs ();
 
@@ -1814,6 +1819,7 @@
 
   POP_NARGOUT ();
   DEC_DEPTH();
+  m_unknown_nargout--;
 }
 
 void
@@ -1822,6 +1828,7 @@
 {
   INC_DEPTH ();
   PUSH_NARGOUT (1);
+  m_unknown_nargout++;
 
   std::vector<int> need_after;
   int fold_slot = -1;
@@ -2100,6 +2107,7 @@
   POP_NARGOUT ();
 
   DEC_DEPTH ();
+  m_unknown_nargout--;
 }
 
 void
@@ -5176,12 +5184,30 @@
 
   arg_name_entry.m_ip_start = CODE_SIZE ();
 
+  // TODO: Kludge alert. Mirror the behaviour in ov_classdef::subsref
+  // where under certain conditions a magic number nargout of -1 is
+  // expected to  maybe return a cs-list. "-1" in this context 
+  // does not have the same meaning as in the VM, where it means
+  // a varargout with only one return symbol 'varargout'.
+  bool m1_magic_nargout = false;
+  if (m_unknown_nargout)
+    {
+      if ((v_types.size () >= 1 && (v_types[0] == '{' || v_types[0] == '.')) ||
+          (v_types.size () >= 2 && (v_types[0] == '(' && v_types[1] == '.')))
+      {
+          m1_magic_nargout = true; 
+      }
+    }
+
   if (first_expression && first_expression->is_identifier ())
     {
       int slot = SLOT (first_expression->name ());
       MAYBE_PUSH_ANON_NARGOUT_OPEXT (nargout);
       PUSH_CODE (INSTR::INDEX_STRUCT_CALL);
-      PUSH_CODE (nargout);
+      if (m1_magic_nargout)
+        PUSH_CODE (-1);
+      else
+        PUSH_CODE (nargout);
       PUSH_CODE (1); // has slot
       PUSH_WSLOT (slot); // the slot
     }
@@ -5189,7 +5215,10 @@
     {
       MAYBE_PUSH_ANON_NARGOUT_OPEXT (nargout);
       PUSH_CODE (INSTR::INDEX_STRUCT_CALL);
-      PUSH_CODE (nargout);
+      if (m1_magic_nargout)
+        PUSH_CODE (-1);
+      else
+        PUSH_CODE (nargout);
       PUSH_SLOT (0); // has slot
       PUSH_WSLOT (0); // slot ignored
     }
--- a/libinterp/parse-tree/pt-bytecode-walk.h	Sat Oct 14 19:13:12 2023 +0200
+++ b/libinterp/parse-tree/pt-bytecode-walk.h	Sun Oct 15 16:50:47 2023 +0200
@@ -197,6 +197,15 @@
     // for anonymous functions.
     stack_frame::local_vars_map *m_anon_local_values = nullptr;
 
+    // TODO: Kludge alert. Mirror the behaviour in ov_classdef::subsref
+    // where under certain conditions a magic number nargout of -1 is
+    // expected to  maybe return a cs-list. "-1" in this context 
+    // does not have the same meaning as in the VM, where it means
+    // a varargout with only one return symbol 'varargout'.
+    //
+    // We need to track "unknown nargout" for this.
+    int m_unknown_nargout = 0;
+
     //
     bool m_is_folding = false;
     std::vector<tree*> m_v_trees_to_fold;