diff libinterp/octave-value/ov-fcn-handle.h @ 26847:8bd9fd99c12a

lazily evaluate fcn handles; fix overload resolution (bug #29447, bug #31821, bug #48802) * ov-fcn-handle.h, ov-fcn-handle.cc (octave_fcn_handle::has_overloads, octave_fcn_handle::builtin_overloads, octave_fcn_handle::overloads): Delete member variables and all uses. (octave_fcn_handle::set_overload, octave_fcn_handle::set_overload, octave_fcn_handle::builtin_type, octave_fcn_handle::is_overloaded): Delete. (octave_fcn_handle::m_scope): New member variable. Store scop where handle is created along with function name to allow proper lookup and overload resolution. (octave_fcn_handle::m_generic_fcn): New member variable. (octave_fcn_handle::function_value, octave_fcn_handle::user_function_value): Store octave_value object containing discovered function in m_generic_fcn so we can safely return a pointer to the underlying function object. (make_fcn_handle, octave_fcn_handle::subsref): Greatly simplify. * pt-eval.cc (tree_evaluator::execute_user_function): Push closure context for any handle created inside a nested function or parent of a nested function. * cellfun.cc (Fcellfun): Eliminate special checks for "overloaded" function handles. * graphics.cc (gh_manager::do_execute_callback): If callback is a function handle, pass it directly to feval instead of extracting function value from it first. * cdef-class.cc (make_fcn_handle): Accept interpreter as argument. Change all uses. Create octave_fcn_handle object with current scope.
author John W. Eaton <jwe@octave.org>
date Tue, 05 Mar 2019 22:30:09 +0000
parents 6e9034836239
children ab97008be411
line wrap: on
line diff
--- a/libinterp/octave-value/ov-fcn-handle.h	Tue Mar 05 07:32:38 2019 +0000
+++ b/libinterp/octave-value/ov-fcn-handle.h	Tue Mar 05 22:30:09 2019 +0000
@@ -33,6 +33,7 @@
 #include "ov-base.h"
 #include "ov-fcn.h"
 #include "ov-typeinfo.h"
+#include "symscope.h"
 
 namespace octave
 {
@@ -56,27 +57,26 @@
   static const std::string anonymous;
 
   octave_fcn_handle (void)
-    : fcn (), nm (), has_overloads (false), overloads (),
-      m_is_nested (false), m_closure_frames (nullptr)
-  { }
-
-  octave_fcn_handle (const std::string& n)
-    : fcn (), nm (n), has_overloads (false), overloads (),
-      m_is_nested (false), m_closure_frames (nullptr)
+    : fcn (), nm (), m_scope (), m_is_nested (false),
+      m_closure_frames (nullptr)
   { }
 
-  octave_fcn_handle (const octave_value& f,  const std::string& n = anonymous);
+  octave_fcn_handle (const octave::symbol_scope& scope, const std::string& n)
+    : fcn (), nm (n), m_scope (scope), m_is_nested (false),
+      m_closure_frames (nullptr)
+  {
+    if (! nm.empty () && nm[0] == '@')
+      nm = nm.substr (1);
+  }
 
-  octave_fcn_handle (const octave_fcn_handle& fh)
-    : octave_base_value (fh), fcn (fh.fcn), nm (fh.nm),
-      has_overloads (fh.has_overloads), overloads (),
-      m_is_nested (fh.m_is_nested), m_closure_frames (fh.m_closure_frames)
-  {
-    for (int i = 0; i < btyp_num_types; i++)
-      builtin_overloads[i] = fh.builtin_overloads[i];
+  octave_fcn_handle (const octave::symbol_scope& scope,
+                     const octave_value& f,
+                     const std::string& n = anonymous);
 
-    overloads = fh.overloads;
-  }
+  octave_fcn_handle (const octave_value& f,
+                     const std::string& n = anonymous);
+
+  octave_fcn_handle (const octave_fcn_handle& fh) = default;
 
   ~octave_fcn_handle (void);
 
@@ -100,23 +100,14 @@
 
   bool is_function_handle (void) const { return true; }
 
-  builtin_type_t builtin_type (void) const { return btyp_func_handle; }
-
-  bool is_overloaded (void) const { return has_overloads; }
-
   bool is_nested (void) const { return m_is_nested; }
 
   dim_vector dims (void) const;
 
-  octave_function * function_value (bool = false)
-  {
-    return fcn.function_value ();
-  }
-
-  octave_user_function * user_function_value (bool = false)
-  {
-    return fcn.user_function_value ();
-  }
+  // FIXME: These must go away.  They don't do the right thing for
+  // scoping or overloads.
+  octave_function * function_value (bool = false);
+  octave_user_function * user_function_value (bool = false);
 
   octave_fcn_handle * fcn_handle_value (bool = false) { return this; }
 
@@ -128,23 +119,6 @@
 
   octave_value workspace (void) const;
 
-  void set_overload (builtin_type_t btyp, const octave_value& ov_fcn)
-  {
-    if (btyp != btyp_unknown)
-      {
-        has_overloads = true;
-        builtin_overloads[btyp] = ov_fcn;
-      }
-
-  }
-
-  void set_overload (const std::string& dispatch_type,
-                     const octave_value& ov_fcn)
-  {
-    has_overloads = true;
-    overloads[dispatch_type] = ov_fcn;
-  }
-
   bool is_equal_to (const octave_fcn_handle&) const;
 
   octave_value convert_to_str_internal (bool pad, bool force, char type) const;
@@ -177,20 +151,22 @@
 
 protected:
 
-  // The function we are handling.
+  // The function we are handling (this should be valid for handles to
+  // anonymous functions and some other special cases).  Otherwise, we
+  // perform dynamic lookup based on the name of the function we are
+  // handling and the scope where the funtion handle object was created.
   octave_value fcn;
 
-  // The name of the handle, including the "@".
+  // The function we would find without considering argument types.  We
+  // cache this value so that the function_value and user_function_value
+  // methods may continue to work.
+  octave_value m_generic_fcn;
+
+  // The name of the handle, not including the "@".
   std::string nm;
 
-  // Whether the function is overloaded at all.
-  bool has_overloads;
-
-  // Overloads for builtin types.  We use array to make lookup faster.
-  octave_value builtin_overloads[btyp_num_types];
-
-  // Overloads for other classes.
-  str_ov_map overloads;
+  // The scope where this object was defined.
+  octave::symbol_scope m_scope;
 
   // TRUE means this is a handle to a nested function.
   bool m_is_nested;