From c9ccdc20a9dea64a608977c351657c01ea085840 Mon Sep 17 00:00:00 2001
From: stepan <stepan.sindelar@oracle.com>
Date: Fri, 20 Jan 2017 12:32:34 +0100
Subject: [PATCH] Internal and group generic dispatch honors __S3MethodsTable__

---
 .../truffle/r/nodes/function/RCallNode.java   |  9 +++---
 .../truffle/r/test/ExpectedTestOutput.test    | 28 +++++++++++++++++++
 .../r/test/functions/TestS3Dispatch.java      | 10 ++++++-
 3 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
index c8ac9b569c..9562c099cb 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
@@ -98,6 +98,7 @@ import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RPromise.Closure;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
+import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.nodes.RFastPathNode;
 import com.oracle.truffle.r.runtime.nodes.RNode;
@@ -293,7 +294,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
             S3Args s3Args;
             RFunction resultFunction;
             if (implicitTypeProfile.profile(type != null)) {
-                Result result = dispatchLookup.execute(frame, builtin.getGenericName(), type, null, frame.materialize(), null);
+                Result result = dispatchLookup.execute(frame, builtin.getGenericName(), type, null, frame.materialize(), REnvironment.baseEnv().getFrame());
                 if (resultIsBuiltinProfile.profile(result.function.isBuiltin())) {
                     s3Args = null;
                 } else {
@@ -330,7 +331,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         S3Args s3Args;
         RFunction resultFunction;
         if (implicitTypeProfile.profile(type != null)) {
-            Result result = dispatchLookup.execute(frame, builtin.getName(), type, null, frame.materialize(), null);
+            Result result = dispatchLookup.execute(frame, builtin.getName(), type, null, frame.materialize(), REnvironment.baseEnv().getFrame());
             if (resultIsBuiltinProfile.profile(result.function.isBuiltin())) {
                 s3Args = null;
             } else {
@@ -402,13 +403,13 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         RStringVector typeX = classHierarchyNodeX.execute(promiseHelperNode.checkEvaluate(frame, args[typeXIdx]));
         Result resultX = null;
         if (implicitTypeProfileX.profile(typeX != null)) {
-            resultX = dispatchLookupX.execute(frame, builtin.getName(), typeX, dispatch.getGroupGenericName(), frame.materialize(), null);
+            resultX = dispatchLookupX.execute(frame, builtin.getName(), typeX, dispatch.getGroupGenericName(), frame.materialize(), REnvironment.baseEnv().getFrame());
         }
         Result resultY = null;
         if (args.length > 1 && dispatch == RDispatch.OPS_GROUP_GENERIC) {
             RStringVector typeY = classHierarchyNodeY.execute(promiseHelperNode.checkEvaluate(frame, args[1]));
             if (implicitTypeProfileY.profile(typeY != null)) {
-                resultY = dispatchLookupY.execute(frame, builtin.getName(), typeY, dispatch.getGroupGenericName(), frame.materialize(), null);
+                resultY = dispatchLookupY.execute(frame, builtin.getName(), typeY, dispatch.getGroupGenericName(), frame.materialize(), REnvironment.baseEnv().getFrame());
             }
         }
 
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index b69fe6363c..6e01d023dd 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -71952,6 +71952,34 @@ $c
 [1] 5
 
 
+##com.oracle.truffle.r.test.functions.TestS3Dispatch.testGenericDispatchThroughMethodsTable#
+#terms(x~z)[1];
+x ~ z
+attr(,"variables")
+list(x, z)
+attr(,"factors")
+  z
+x 0
+z 1
+attr(,"term.labels")
+[1] "z"
+attr(,"order")
+[1] 1
+attr(,"intercept")
+[1] 1
+attr(,"response")
+[1] 1
+attr(,".Environment")
+<environment: R_GlobalEnv>
+
+##com.oracle.truffle.r.test.functions.TestS3Dispatch.testGenericDispatchThroughMethodsTable#
+#{ assign('Ops.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; x+x; }
+[1] 42
+
+##com.oracle.truffle.r.test.functions.TestS3Dispatch.testGenericDispatchThroughMethodsTable#
+#{ assign('[[.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; x[[99]]; }
+[1] 42
+
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.testMathGroupDispatch#
 #{x<--7;class(x)<-"foo";Math.foo<-function(z){-z;};log(x);}
 [1] 7
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java
index f122330964..bc847b5fab 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -134,6 +134,14 @@ public class TestS3Dispatch extends TestRBase {
         assertEval("f.default<-function(abc, bbb, ...)list(abc, bbb, ...); f<-function(x,...)UseMethod('f'); f(13, ab=42, b=1, c=5);");
     }
 
+    @Test
+    public void testGenericDispatchThroughMethodsTable() {
+        // Note: `[.term` is "private" in stats, but it has entry in __S3MethodsTable__
+        assertEval("terms(x~z)[1];");
+        assertEval("{ assign('Ops.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; x+x; }");
+        assertEval("{ assign('[[.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; x[[99]]; }");
+    }
+
     @Override
     public String getTestDir() {
         return "functions/S3";
-- 
GitLab