From d521a32198ad7a99fd35d29a20bb4a91846b03d0 Mon Sep 17 00:00:00 2001 From: Lukas Stadler <lukas.stadler@oracle.com> Date: Mon, 19 Feb 2018 10:41:49 +0100 Subject: [PATCH] handle non-scalar constants inside functions in "identical" --- .../r/runtime/nodes/IdenticalVisitor.java | 70 ++++++++++++++++++- .../truffle/r/test/ExpectedTestOutput.test | 7 ++ .../test/builtins/TestBuiltin_identical.java | 1 + 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IdenticalVisitor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IdenticalVisitor.java index 90cafa94aa..a01368e3ae 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IdenticalVisitor.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IdenticalVisitor.java @@ -22,6 +22,16 @@ */ package com.oracle.truffle.r.runtime.nodes; +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.r.runtime.data.RAttributable; +import com.oracle.truffle.r.runtime.data.RPairList; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.env.REnvironment; + +/** + * Currently, this visitor is only necessary because we don't treat the body of an RFunction as a + * pairlist. It's slightly inaccurate in how it treats constants, attributes, etc. + */ public final class IdenticalVisitor extends RSyntaxArgVisitor<Boolean, RSyntaxElement> { @Override @@ -41,7 +51,65 @@ public final class IdenticalVisitor extends RSyntaxArgVisitor<Boolean, RSyntaxEl if (!(arg instanceof RSyntaxConstant)) { return false; } - return element.getValue().equals(((RSyntaxConstant) arg).getValue()); + return identicalValue(element.getValue(), ((RSyntaxConstant) arg).getValue()); + } + + private Boolean identicalValue(Object value, Object otherValue) { + if (value instanceof Number || value instanceof String) { + return value.equals(otherValue); + } + if (value instanceof RAttributable) { + if (!(otherValue instanceof RAttributable)) { + return false; + } + if (!identicalAttributes((RAttributable) value, (RAttributable) otherValue)) { + return false; + } + if (!identicalAttributes((RAttributable) otherValue, (RAttributable) value)) { + return false; + } + } + if (value instanceof RAbstractVector) { + RAbstractVector vector = (RAbstractVector) value; + if (!(otherValue instanceof RAbstractVector)) { + return false; + } + RAbstractVector otherVector = (RAbstractVector) otherValue; + if (vector.getLength() != otherVector.getLength() || vector.getRType() != otherVector.getRType()) { + return false; + } + for (int i = 0; i < vector.getLength(); i++) { + if (!identicalValue(vector.getDataAtAsObject(i), otherVector.getDataAtAsObject(i))) { + return false; + } + } + return true; + } + if (value instanceof RPairList && ((RPairList) value).isLanguage()) { + if (!(otherValue instanceof RPairList && ((RPairList) otherValue).isLanguage())) { + return false; + } + return accept(((RPairList) value).getSyntaxElement(), ((RPairList) otherValue).getSyntaxElement()); + } + if (value instanceof REnvironment) { + return value == otherValue; + } + return value == otherValue; + } + + private boolean identicalAttributes(RAttributable attributable, RAttributable otherAttributable) { + DynamicObject attributes = attributable.getAttributes(); + if (attributes != null) { + DynamicObject otherAttributes = otherAttributable.getAttributes(); + for (Object key : attributes.getShape().getKeys()) { + Object attributeValue = attributes.get(key); + Object otherAttributeValue = otherAttributes == null ? null : otherAttributes.get(key); + if ((attributeValue == null) != (otherAttributeValue == null) || !identicalValue(attributeValue, otherAttributeValue)) { + return false; + } + } + } + return true; } @Override 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 28e719055c..963736621e 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 @@ -29927,6 +29927,13 @@ attr(,"Rd_tag") #a <- quote(a(100)); b <- quote(a(101)); identical(a,b) [1] FALSE +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical# +#e1 <- quote(a+1); e2 <- quote(a+2); identical(e1, e2); e2[[3]] <- c(1,2,3); identical(e1, e2); e1[[3]] <- c(1,2,3); identical(e1, e2); attr(e2[[3]], 'foo') <- 'bar'; identical(e1, e2) +[1] FALSE +[1] FALSE +[1] TRUE +[1] FALSE + ##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical# #identical(pairlist(1, pairlist('foo')), pairlist(1, pairlist('bar'))) [1] FALSE diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java index d9e8d9df8e..9aa604764d 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java @@ -271,6 +271,7 @@ public class TestBuiltin_identical extends TestBase { assertEval("a <- quote(a(100)); b <- quote(a(100)); attr(a[[2]], 'foo') <- 'bar'; b[[2]] <- a[[2]]; identical(a,b)"); assertEval("a <- quote(a(100)); b <- quote(a(100)); attr(b[[2]], 'foo') <- 'baz'; attr(a[[2]], 'foo') <- 'bar'; identical(a,b)"); assertEval("a <- quote(a(100)); b <- quote(a(100)); attr(b[[2]], 'foo') <- 'bar'; attr(a[[2]], 'foo') <- 'bar'; identical(a,b)"); + assertEval("e1 <- quote(a+1); e2 <- quote(a+2); identical(e1, e2); e2[[3]] <- c(1,2,3); identical(e1, e2); e1[[3]] <- c(1,2,3); identical(e1, e2); attr(e2[[3]], 'foo') <- 'bar'; identical(e1, e2)"); } @Test -- GitLab