changeset 32410:554a932fc6d0

Fix nargout when calling class subsref method (bug #63841) * libinterp/octave-value/ov-class.cc (octave_class::subsref), libinterp/octave-value/ov-classdef.cc (octave_classdef::subsref): Do not change value of nargout if it is positive. Return a cs-list only if the caller accepts more than one output. * libinterp/parse-tree/pt-eval.cc (tree_evaluator::convert_to_const_vector): Use nargout=-1 to indicate unknown number of output arguments. (tree_evaluator::execute_builtin_function, tree_evaluator::execute_mex_function, tree_evaluator::execute_user_function): if nargout negative, use argout=1 * libinterp/parse-tree/pt-tm-const.cc (tm_row_const::init), libinterp/parse-tree/pt-binop.cc (tree_binary_expression::evaluate), libinterp/parse-tree/pt-cbinop.cc (tree_compound_binary_expression::evaluate), libinterp/parse-tree/pt-unop.cc (tree_prefix_expression::evaluate, tree_postfix_expression::evaluate): Use nargout=-1 to indicate unknown number of output arguments.
author Fernando Alvarruiz <feralber@upvnet.upv.es>
date Sat, 15 Apr 2023 10:37:37 +0200
parents 818698c4f296
children 768df05d04f3
files libinterp/octave-value/ov-class.cc libinterp/octave-value/ov-classdef.cc libinterp/parse-tree/pt-binop.cc libinterp/parse-tree/pt-cbinop.cc libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-tm-const.cc libinterp/parse-tree/pt-unop.cc
diffstat 7 files changed, 98 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/octave-value/ov-class.cc	Fri Oct 13 17:56:34 2023 +0200
+++ b/libinterp/octave-value/ov-class.cc	Sat Apr 15 10:37:37 2023 +0200
@@ -465,32 +465,44 @@
           m_count++;
           args(0) = octave_value (this);
 
-          // FIXME: for Matlab compatibility, let us attempt to set up a proper
-          // value for nargout at least in the simple case where the
+          // If the number of output arguments is unknown, attempt to set up
+          // a proper value for nargout at least in the simple case where the
           // cs-list-type expression - i.e., {} or ().x, is the leading one.
-          // Note that Octave does not actually need this, since it will
-          // be able to properly react to varargout a posteriori.
-          bool maybe_cs_list_query = (type[0] == '.' || type[0] == '{'
-                                      || (type.length () > 1 && type[0] == '('
-                                          && type[1] == '.'));
-
-          int true_nargout = nargout;
-
-          if (maybe_cs_list_query)
+          if (nargout <= 0)
             {
-              // Set up a proper nargout for the subsref call by calling numel.
-              octave_value_list tmp;
-              if (type[0] != '.') tmp = idx.front ();
-              true_nargout = xnumel (tmp);
+              bool maybe_cs_list_query = (type[0] == '.' || type[0] == '{'
+                                          || (type.length () > 1 && type[0] == '('
+                                              && type[1] == '.'));
+
+              if (maybe_cs_list_query)
+                {
+                  // Set up a proper nargout for the subsref call by calling numel.
+                  octave_value_list tmp;
+                  int nout;
+                  if (type[0] != '.') tmp = idx.front ();
+                  nout = xnumel (tmp);
+                  if (nargout != 0 || nout > 1)
+                    nargout = nout;
+                }
+              else if (nargout < 0)
+                nargout = 1;
             }
 
-          retval = interp.feval (meth.function_value (), args, true_nargout);
-
-          // Since we're handling subsref, if the list has more than one
-          // element, return it as a comma-separated list so that we can
-          // pass it to the evaluator
-          if (retval.length () > 1)
-            retval = octave_value (retval);
+          retval = interp.feval (meth.function_value (), args, nargout);
+
+          // Since we're handling subsref, if the list has more than one element
+          // and the caller to subsref accepts more that one output, return
+          // the elements as a comma-separated list so that we can pass it to the
+          // evaluator
+          if (retval.length () > 1 && (nargout < 0 || nargout >1))
+            {
+              if (nargout <= 0 || nargout>=retval.length())
+                // Take the whole list
+                retval = octave_value (retval);
+              else
+                // Take nargout elements of the list
+                retval = octave_value(retval.slice(0,nargout));
+            }
         }
       else
         {
--- a/libinterp/octave-value/ov-classdef.cc	Fri Oct 13 17:56:34 2023 +0200
+++ b/libinterp/octave-value/ov-classdef.cc	Sat Apr 15 10:37:37 2023 +0200
@@ -91,28 +91,44 @@
           m_count++;
           args(0) = octave_value (this);
 
-          // Attempt to set up a proper value for nargout at least in the
-          // simple case where the cs-list-type expression - i.e., {} or
-          // ().x, is the leading one.
-          bool maybe_cs_list_query = (type[0] == '.' || type[0] == '{'
-                                      || (type.length () > 1 && type[0] == '('
-                                          && type[1] == '.'));
+          // If the number of output arguments is unknown, attempt to set up
+          // a proper value for nargout at least in the simple case where the
+          // cs-list-type expression - i.e., {} or ().x, is the leading one.
+          if (nargout <= 0)
+            {
+              bool maybe_cs_list_query = (type[0] == '.' || type[0] == '{'
+                                          || (type.length () > 1 && type[0] == '('
+                                              && type[1] == '.'));
 
-          if (maybe_cs_list_query)
-            {
-              // Set up a proper nargout for the subsref call by calling numel.
-              octave_value_list tmp;
-              if (type[0] != '.') tmp = idx.front ();
-              nargout = xnumel (tmp);
+              if (maybe_cs_list_query)
+                {
+                  // Set up a proper nargout for the subsref call by calling numel.
+                  octave_value_list tmp;
+                  int nout;
+                  if (type[0] != '.') tmp = idx.front ();
+                  nout = xnumel (tmp);
+                  if (nargout != 0 || nout > 1)
+                    nargout = nout;
+                }
+              else if (nargout < 0)
+                nargout = 1;
             }
 
           retval = meth.execute (args, nargout, true, "subsref");
 
-          // Since we're handling subsref, if the list has more than one
-          // element, return it as a comma-separated list so that we can
-          // pass it to the evaluator
-          if (retval.length () > 1)
-            retval = octave_value (retval);
+          // Since we're handling subsref, if the list has more than one element
+          // and the caller to subsref accepts more that one output, return
+          // the elements as a comma-separated list so that we can pass it to the
+          // evaluator
+          if (retval.length () > 1 && (nargout < 0 || nargout >1))
+            {
+              if (nargout <= 0 || nargout>=retval.length())
+                // Take the whole list
+                retval = octave_value (retval);
+              else
+                // Take nargout elements of the list
+                retval = octave_value(retval.slice(0,nargout));
+            }
 
           return retval;
         }
--- a/libinterp/parse-tree/pt-binop.cc	Fri Oct 13 17:56:34 2023 +0200
+++ b/libinterp/parse-tree/pt-binop.cc	Sat Apr 15 10:37:37 2023 +0200
@@ -71,11 +71,13 @@
 {
   if (m_lhs)
     {
-      octave_value a = m_lhs->evaluate (tw);
+      // Evaluate with unknown number of output arguments
+      octave_value a = m_lhs->evaluate (tw, -1);
 
       if (a.is_defined () && m_rhs)
         {
-          octave_value b = m_rhs->evaluate (tw);
+          // Evaluate with unknown number of output arguments
+          octave_value b = m_rhs->evaluate (tw, -1);
 
           if (b.is_defined ())
             {
--- a/libinterp/parse-tree/pt-cbinop.cc	Fri Oct 13 17:56:34 2023 +0200
+++ b/libinterp/parse-tree/pt-cbinop.cc	Sat Apr 15 10:37:37 2023 +0200
@@ -42,11 +42,13 @@
 
   if (m_lhs)
     {
-      octave_value a = m_lhs->evaluate (tw);
+      // Evaluate with unknown number of output arguments
+      octave_value a = m_lhs->evaluate (tw, -1);
 
       if (a.is_defined () && m_rhs)
         {
-          octave_value b = m_rhs->evaluate (tw);
+          // Evaluate with unknown number of output arguments
+          octave_value b = m_rhs->evaluate (tw, -1);
 
           if (b.is_defined ())
             {
--- a/libinterp/parse-tree/pt-eval.cc	Fri Oct 13 17:56:34 2023 +0200
+++ b/libinterp/parse-tree/pt-eval.cc	Sat Apr 15 10:37:37 2023 +0200
@@ -2306,7 +2306,8 @@
       if (! elt)
         break;
 
-      octave_value tmp = elt->evaluate (*this);
+      // Evaluate with unknown number of output arguments
+      octave_value tmp = elt->evaluate (*this, -1);
 
       if (tmp.is_cs_list ())
         {
@@ -3412,6 +3413,11 @@
 
   octave_builtin::fcn fcn = builtin_function.function ();
 
+  // If number of outputs unknown (and this is not a complete statement),
+  // pass nargout=1 to the function being called
+  if (nargout < 0)
+    nargout = 1;
+
   if (fcn)
     retval = (*fcn) (args, nargout);
   else
@@ -3455,6 +3461,11 @@
 
   profiler::enter<octave_mex_function> block (m_profiler, mex_function);
 
+  // If number of outputs unknown (and this is not a complete statement),
+  // pass nargout=1 to the function being called
+  if (nargout < 0)
+    nargout = 1;
+
   retval = call_mex (mex_function, args, nargout);
 
   return retval;
@@ -3529,6 +3540,11 @@
 
   int nargin = args.length ();
 
+  // If number of outputs unknown (and this is not a complete statement),
+  // pass nargout=1 to the function being called
+  if (nargout < 0)
+    nargout = 1;
+  
   if (user_function.is_classdef_constructor ())
     {
       if (nargin > 0)
--- a/libinterp/parse-tree/pt-tm-const.cc	Fri Oct 13 17:56:34 2023 +0200
+++ b/libinterp/parse-tree/pt-tm-const.cc	Sat Apr 15 10:37:37 2023 +0200
@@ -182,7 +182,8 @@
     {
       octave_quit ();
 
-      octave_value tmp = elt->evaluate (tw);
+      // Evaluate with unknown number of output arguments
+      octave_value tmp = elt->evaluate (tw, -1);
 
       if (tmp.is_undefined ())
         error ("undefined element in matrix list");
--- a/libinterp/parse-tree/pt-unop.cc	Fri Oct 13 17:56:34 2023 +0200
+++ b/libinterp/parse-tree/pt-unop.cc	Sat Apr 15 10:37:37 2023 +0200
@@ -77,7 +77,8 @@
         }
       else
         {
-          octave_value op_val = m_op->evaluate (tw);
+          // Evaluate with unknown number of output arguments
+          octave_value op_val = m_op->evaluate (tw, -1);
 
           if (op_val.is_defined ())
             {
@@ -138,7 +139,8 @@
         }
       else
         {
-          octave_value op_val = m_op->evaluate (tw);
+          // Evaluate with unknown number of output arguments
+          octave_value op_val = m_op->evaluate (tw, -1);
 
           if (op_val.is_defined ())
             {