Skip to content
Snippets Groups Projects
Commit 70b874cd authored by Lukas Stadler's avatar Lukas Stadler Committed by Mick Jordan
Browse files

change S3 lookup order to consider enclosing env and method table simultaneously

parent 0d6f5ad9
Branches
No related tags found
No related merge requests found
...@@ -399,6 +399,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS ...@@ -399,6 +399,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
@Cached("createUninitializedExplicitCall()") FunctionDispatch call) { @Cached("createUninitializedExplicitCall()") FunctionDispatch call) {
Object[] args = explicitArgs != null ? ((RArgsValuesAndNames) explicitArgs.execute(frame)).getArguments() : callArguments.evaluateFlattenObjects(frame, lookupVarArgs(frame)); Object[] args = explicitArgs != null ? ((RArgsValuesAndNames) explicitArgs.execute(frame)).getArguments() : callArguments.evaluateFlattenObjects(frame, lookupVarArgs(frame));
ArgumentsSignature argsSignature = explicitArgs != null ? ((RArgsValuesAndNames) explicitArgs.execute(frame)).getSignature() : callArguments.flattenNames(lookupVarArgs(frame));
RBuiltinDescriptor builtin = builtinProfile.profile(function.getRBuiltin()); RBuiltinDescriptor builtin = builtinProfile.profile(function.getRBuiltin());
RDispatch dispatch = builtin.getDispatch(); RDispatch dispatch = builtin.getDispatch();
...@@ -462,7 +463,6 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS ...@@ -462,7 +463,6 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
} }
resultFunction = result.function; resultFunction = result.function;
} }
ArgumentsSignature argsSignature = explicitArgs != null ? ((RArgsValuesAndNames) explicitArgs.execute(frame)).getSignature() : callArguments.flattenNames(lookupVarArgs(frame));
return call.execute(frame, resultFunction, new RArgsValuesAndNames(args, argsSignature), s3Args); return call.execute(frame, resultFunction, new RArgsValuesAndNames(args, argsSignature), s3Args);
} }
......
...@@ -101,22 +101,17 @@ public abstract class S3FunctionLookupNode extends RBaseNode { ...@@ -101,22 +101,17 @@ public abstract class S3FunctionLookupNode extends RBaseNode {
@TruffleBoundary @TruffleBoundary
private static Result performLookup(MaterializedFrame callerFrame, String genericName, String groupName, RStringVector type, boolean nextMethod, LookupOperation op, GetMethodsTable getTable) { private static Result performLookup(MaterializedFrame callerFrame, String genericName, String groupName, RStringVector type, boolean nextMethod, LookupOperation op, GetMethodsTable getTable) {
Result result; Result result;
// look for a generic function reachable from the caller frame
if ((result = lookupClassGenerics(callerFrame, genericName, groupName, type, nextMethod, false, op)) != null) {
return result;
}
Object methodsTable = getTable.get(); Object methodsTable = getTable.get();
if (methodsTable instanceof RPromise) { if (methodsTable instanceof RPromise) {
methodsTable = PromiseHelperNode.evaluateSlowPath(null, (RPromise) methodsTable); methodsTable = PromiseHelperNode.evaluateSlowPath(null, (RPromise) methodsTable);
} }
MaterializedFrame methodsTableFrame = methodsTable == null ? null : ((REnvironment) methodsTable).getFrame(); MaterializedFrame methodsTableFrame = methodsTable == null ? null : ((REnvironment) methodsTable).getFrame();
if (methodsTableFrame != null) { // look for a generic function reachable from the caller frame
// look for a generic function in the methods table if ((result = lookupClassGenerics(callerFrame, methodsTableFrame, genericName, groupName, type, nextMethod, op)) != null) {
if ((result = lookupClassGenerics(methodsTableFrame, genericName, groupName, type, nextMethod, true, op)) != null) { return result;
return result;
}
} }
// look for the default method // look for the default method
String functionName = genericName + RRuntime.RDOT + RRuntime.DEFAULT; String functionName = genericName + RRuntime.RDOT + RRuntime.DEFAULT;
RFunction function = checkPromise(op.read(callerFrame, functionName, false)); RFunction function = checkPromise(op.read(callerFrame, functionName, false));
...@@ -129,19 +124,29 @@ public abstract class S3FunctionLookupNode extends RBaseNode { ...@@ -129,19 +124,29 @@ public abstract class S3FunctionLookupNode extends RBaseNode {
return null; return null;
} }
private static Result lookupClassGenerics(MaterializedFrame callerFrame, String genericName, String groupName, RStringVector type, boolean nextMethod, boolean inMethodsTable, LookupOperation op) { private static Result lookupClassGenerics(MaterializedFrame callerFrame, MaterializedFrame methodsTableFrame, String genericName, String groupName, RStringVector type, boolean nextMethod,
LookupOperation op) {
Result result = null; Result result = null;
for (int i = nextMethod ? 1 : 0; i < type.getLength(); i++) { for (int i = nextMethod ? 1 : 0; i < type.getLength(); i++) {
String clazzName = type.getDataAt(i); String clazzName = type.getDataAt(i);
boolean groupMatch = false; boolean groupMatch = false;
String functionName = genericName + RRuntime.RDOT + type.getDataAt(i); String functionName = genericName + RRuntime.RDOT + type.getDataAt(i);
RFunction function = checkPromise(op.read(callerFrame, functionName, inMethodsTable)); RFunction function = checkPromise(op.read(callerFrame, functionName, false));
if (function == null) {
if (methodsTableFrame != null) {
function = checkPromise(op.read(methodsTableFrame, functionName, true));
}
if (function == null && groupName != null) { if (function == null && groupName != null) {
groupMatch = true; groupMatch = true;
functionName = groupName + RRuntime.RDOT + clazzName; functionName = groupName + RRuntime.RDOT + clazzName;
function = checkPromise(op.read(callerFrame, functionName, inMethodsTable)); function = checkPromise(op.read(callerFrame, functionName, false));
if (function == null && methodsTableFrame != null) {
function = checkPromise(op.read(methodsTableFrame, functionName, true));
}
}
} }
if (function != null) { if (function != null) {
......
...@@ -54902,6 +54902,14 @@ attr(,"class") ...@@ -54902,6 +54902,14 @@ attr(,"class")
attr(,"class") attr(,"class")
[1] "foo" [1] "foo"
   
##com.oracle.truffle.r.test.functions.TestS3Dispatch.testMethodTableDispatch
#t <- ts(1:3); class(t) <- c('ts', 'foo'); print.foo <- function(x, ...) 'foo'; print(t)
Time Series:
Start = 1
End = 3
Frequency = 1
[1] 1 2 3
##com.oracle.truffle.r.test.functions.TestS3Dispatch.testNextMethod ##com.oracle.truffle.r.test.functions.TestS3Dispatch.testNextMethod
#{ f.default<-function(x, a=7) a; f.foo<-function(x, a=v) { b<-NextMethod("f"); v=42; c(a,b) }; x<-1; class(x)<-"foo"; f<-function(x) UseMethod("f"); f(x) } #{ f.default<-function(x, a=7) a; f.foo<-function(x, a=v) { b<-NextMethod("f"); v=42; c(a,b) }; x<-1; class(x)<-"foo"; f<-function(x) UseMethod("f"); f(x) }
[1] 42 7 [1] 42 7
...@@ -111,4 +111,11 @@ public class TestS3Dispatch extends TestBase { ...@@ -111,4 +111,11 @@ public class TestS3Dispatch extends TestBase {
public void testComplexGroupDispatch() { public void testComplexGroupDispatch() {
assertEval("{x<--7+2i;class(x)<-\"foo\";Complex.foo<-function(z){1;};Im(x);}"); assertEval("{x<--7+2i;class(x)<-\"foo\";Complex.foo<-function(z){1;};Im(x);}");
} }
@Test
public void testMethodTableDispatch() {
// this test ensures that print.ts is found in the method table before print.foo is found in
// the calling environment
assertEval("t <- ts(1:3); class(t) <- c('ts', 'foo'); print.foo <- function(x, ...) 'foo'; print(t)");
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment