diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java index 31c17451af606214a9552bd2cf6d5a7487a458f8..1c16340d0c36dc69c1f7d718887e478a23c8e071 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java @@ -49,7 +49,6 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; @@ -85,7 +84,7 @@ public abstract class Array extends RBuiltinNode { @Override protected void createCasts(CastBuilder casts) { Function<Object, Object> argType = this::argType; - casts.arg("data").mustBe(instanceOf(RAbstractListVector.class).or(numericValue()).or(stringValue()).or(complexValue().or(rawValue())), + casts.arg("data").mustBe(abstractVectorValue(), RError.SHOW_CALLER, RError.Message.MUST_BE_VECTOR_BUT_WAS, "data", argType); casts.arg("dim").asIntegerVector().mustBe(notEmpty(), RError.SHOW_CALLER, RError.Message.CANNOT_BE_LENGTH, "dims", 0); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DuplicatedFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DuplicatedFunctions.java index 8d3e7cd3cda9aadd72f58434d70fd1a647a92876..8e2b60251006dc758d19cd5ff7ef30c96a181261 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DuplicatedFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DuplicatedFunctions.java @@ -11,26 +11,30 @@ package com.oracle.truffle.r.nodes.builtin.base; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.binary.CastTypeNode; import com.oracle.truffle.r.nodes.binary.CastTypeNodeGen; import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.unary.TypeofNode; import com.oracle.truffle.r.nodes.unary.TypeofNodeGen; +import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RLogicalVector; -import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; import com.oracle.truffle.r.runtime.nodes.DuplicationHelper; public class DuplicatedFunctions { @@ -39,8 +43,24 @@ public class DuplicatedFunctions { @Child protected CastTypeNode castTypeNode; @Child protected TypeofNode typeof; - protected boolean isIncomparable(byte incomparables) { - return incomparables == RRuntime.LOGICAL_TRUE; + private final ConditionProfile incomparable = ConditionProfile.createBinaryProfile(); + + protected void casts(CastBuilder casts) { + casts.arg("x").mustBe(nullValue().or(abstractVectorValue()), RError.SHOW_CALLER, RError.Message.GENERIC, + "duplicated() applies only to vectors").asVector(); + casts.arg("fromLast").asLogicalVector().findFirst(); + } + + protected boolean isIncomparable(RAbstractVector incomparables) { + if (incomparable.profile(incomparables.getLength() == 1 && incomparables instanceof RLogicalVector && ((RAbstractLogicalVector) incomparables).getDataAt(0) == RRuntime.LOGICAL_FALSE)) { + return false; + } else { + return true; + } + } + + protected boolean notAbstractVector(Object o) { + return !(o instanceof RAbstractVector); } protected boolean empty(RAbstractContainer x) { @@ -61,45 +81,45 @@ public class DuplicatedFunctions { @Override protected void createCasts(CastBuilder casts) { - casts.toLogical(2).toInteger(3); + casts(casts); + // currently not supported and not tested, but NA is a correct value (the same for empty + // vectors) whereas 0 is not (throws an error) + casts.arg("nmax").asIntegerVector().findFirst(RRuntime.INT_NA); } @TruffleBoundary - protected static RLogicalVector analyzeAndCreateResult(RAbstractContainer x, RAbstractContainer incomparables, byte fromLast) { + protected static RLogicalVector analyzeAndCreateResult(RAbstractVector x, RAbstractVector incomparables, byte fromLast) { DuplicationHelper ds = DuplicationHelper.analyze(x, incomparables, false, RRuntime.fromLogical(fromLast)); return RDataFactory.createLogicalVector(ds.getDupVec(), RDataFactory.COMPLETE_VECTOR); } - @SuppressWarnings("unused") - @Specialization - protected RLogicalVector duplicated(RNull x, Object incomparables, byte fromLast, int nmax) { - return RDataFactory.createEmptyLogicalVector(); - } - @Specialization(guards = {"!isIncomparable(incomparables)", "!empty(x)"}) - protected RLogicalVector duplicatedFalseIncomparables(RAbstractVector x, @SuppressWarnings("unused") byte incomparables, byte fromLast, @SuppressWarnings("unused") int nmax) { + protected RLogicalVector duplicatedFalseIncomparables(RAbstractVector x, @SuppressWarnings("unused") RAbstractVector incomparables, byte fromLast, @SuppressWarnings("unused") int nmax) { return analyzeAndCreateResult(x, null, fromLast); } @Specialization(guards = {"isIncomparable(incomparables)", "!empty(x)"}) - protected RLogicalVector duplicatedTrueIncomparables(RAbstractVector x, byte incomparables, byte fromLast, @SuppressWarnings("unused") int nmax) { + protected RLogicalVector duplicatedTrueIncomparables(RAbstractVector x, RAbstractVector incomparables, byte fromLast, @SuppressWarnings("unused") int nmax) { initChildren(); RType xType = typeof.execute(x); RAbstractVector vector = (RAbstractVector) (castTypeNode.execute(incomparables, xType)); return analyzeAndCreateResult(x, vector, fromLast); } - @Specialization(guards = {"!empty(x)"}) - protected RLogicalVector duplicated(RAbstractContainer x, RAbstractContainer incomparables, byte fromLast, @SuppressWarnings("unused") int nmax) { + @SuppressWarnings("unused") + @Specialization(guards = {"notAbstractVector(incomparables)", "!empty(x)"}) + protected RLogicalVector duplicatedTrueIncomparables(RAbstractVector x, Object incomparables, byte fromLast, int nmax) { initChildren(); RType xType = typeof.execute(x); - return analyzeAndCreateResult(x, (RAbstractContainer) (castTypeNode.execute(incomparables, xType)), fromLast); + // TODO: this is not quite correct, as passing expression generated some obscure error + // message, but is it worth fixing + throw RError.error(RError.SHOW_CALLER, RError.Message.CANNOT_COERCE, ((RTypedValue) incomparables).getRType().getName(), xType.getName()); } @SuppressWarnings("unused") @Specialization(guards = "empty(x)") - protected RLogicalVector duplicatedEmpty(RAbstractContainer x, RAbstractContainer incomparables, byte fromLast, int nmax) { - return RDataFactory.createLogicalVector(0); + protected RLogicalVector duplicatedEmpty(RAbstractVector x, Object incomparables, byte fromLast, int nmax) { + return RDataFactory.createEmptyLogicalVector(); } } @@ -108,40 +128,36 @@ public class DuplicatedFunctions { @Override protected void createCasts(CastBuilder casts) { - casts.toLogical(2); + casts(casts); } @SuppressWarnings("unused") @Specialization(guards = {"!isIncomparable(incomparables)", "!empty(x)"}) - protected int anyDuplicatedFalseIncomparables(RAbstractVector x, byte incomparables, byte fromLast) { + protected int anyDuplicatedFalseIncomparables(RAbstractVector x, RAbstractVector incomparables, byte fromLast) { return DuplicationHelper.analyze(x, null, true, RRuntime.fromLogical(fromLast)).getIndex(); } @Specialization(guards = {"isIncomparable(incomparables)", "!empty(x)"}) - protected int anyDuplicatedTrueIncomparables(RAbstractVector x, byte incomparables, byte fromLast) { + protected int anyDuplicatedTrueIncomparables(RAbstractVector x, RAbstractVector incomparables, byte fromLast) { initChildren(); RType xType = typeof.execute(x); - RAbstractVector vector = (RAbstractVector) (castTypeNode.execute(incomparables, xType)); - return DuplicationHelper.analyze(x, vector, true, RRuntime.fromLogical(fromLast)).getIndex(); + return DuplicationHelper.analyze(x, (RAbstractVector) (castTypeNode.execute(incomparables, xType)), true, RRuntime.fromLogical(fromLast)).getIndex(); } - @Specialization(guards = {"!empty(x)"}) - protected int anyDuplicated(RAbstractContainer x, RAbstractContainer incomparables, byte fromLast) { + @Specialization(guards = {"notAbstractVector(incomparables)", "!empty(x)"}) + protected int anyDuplicatedTrueIncomparables(RAbstractVector x, Object incomparables, @SuppressWarnings("unused") byte fromLast) { initChildren(); RType xType = typeof.execute(x); - return DuplicationHelper.analyze(x, (RAbstractContainer) (castTypeNode.execute(incomparables, xType)), true, RRuntime.fromLogical(fromLast)).getIndex(); + // TODO: this is not quite correct, as passing expression generated some obscure error + // message, but is it worth fixing + throw RError.error(RError.SHOW_CALLER, RError.Message.CANNOT_COERCE, ((RTypedValue) incomparables).getRType().getName(), xType.getName()); } @SuppressWarnings("unused") @Specialization(guards = "empty(x)") - protected int anyDuplicatedEmpty(RAbstractContainer x, RAbstractContainer incomparables, byte fromLast) { + protected int anyDuplicatedEmpty(RAbstractVector x, Object incomparables, byte fromLast) { return 0; } - @SuppressWarnings("unused") - @Specialization - protected int anyDuplicatedNull(RNull x, RAbstractContainer incomparables, byte fromLast) { - return 0; - } } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java index f0a8f2f83a93897325ddd2e50af2086ebc9416ef..c3f3da8836c31696bc97470853c72e62ebe4ff46 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java @@ -64,6 +64,7 @@ import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; @@ -995,6 +996,10 @@ public final class CastBuilder { return integerValue().or(doubleValue()).or(logicalValue()); } + public static ArgumentTypeFilter<Object, Object> abstractVectorValue() { + return numericValue().or(stringValue()).or(complexValue()).or(rawValue()).or(instanceOf(RAbstractListVector.class)); + } + public static TypePredicateArgumentFilter<Object, String> scalarStringValue() { return predefFilters().scalarStringValue(); } 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 f1dc824c72aaca9c94b7fa3e2124a04d6450d925..4c23ed736ab12758dee7617b052ceaef580c5dda 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 @@ -18164,6 +18164,11 @@ logical(0) #{ duplicated(c(1,2,1)) } [1] FALSE FALSE TRUE +##com.oracle.truffle.r.test.builtins.TestBuiltin_duplicated.testDuplicated +#{ duplicated(c(1,2,1), incomparables=function() 42) } +Error in duplicated.default(c(1, 2, 1), incomparables = function() 42) : + cannot coerce type 'closure' to vector of type 'double' + ##com.oracle.truffle.r.test.builtins.TestBuiltin_duplicated.testDuplicated #{ duplicated(c(1,2,3,2), incomparables = c(2+6i)) } [1] FALSE FALSE FALSE FALSE @@ -18210,6 +18215,14 @@ In duplicated.default(c(1L, 2L, 1L, 1L, 3L, 2L), incomparables = "cat") : #{ duplicated(list(76.5, 5L, 5L, 76.5, 5, 5), incomparables = c(5L, 76.5)) } [1] FALSE FALSE TRUE FALSE FALSE FALSE +##com.oracle.truffle.r.test.builtins.TestBuiltin_duplicated.testDuplicated +#{ x<-function() 42; duplicated(x) } +Error in duplicated.default(x) : duplicated() applies only to vectors + +##com.oracle.truffle.r.test.builtins.TestBuiltin_duplicated.testDuplicated +#{ x<-quote(f(7, 42)); duplicated(x) } +Error in duplicated.default(x) : duplicated() applies only to vectors + ##com.oracle.truffle.r.test.builtins.TestBuiltin_duplicated.testDuplicated #{duplicated(c("abc"))} [1] FALSE diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_duplicated.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_duplicated.java index f2a56bb64279834f67bf8aaf1561f73aab866c94..a1eb5d73a1b0199b0680eabeb57f843bdd75477a 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_duplicated.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_duplicated.java @@ -130,5 +130,10 @@ public class TestBuiltin_duplicated extends TestBase { assertEval(Output.IgnoreWarningContext, "{ duplicated(c(1,2,3,2), incomparables = c(2+6i)) }"); assertEval("{ duplicated(NULL, 0); }"); + + assertEval("{ x<-quote(f(7, 42)); duplicated(x) }"); + assertEval("{ x<-function() 42; duplicated(x) }"); + assertEval(Output.IgnoreErrorMessage, "{ duplicated(c(1,2,1), incomparables=function() 42) }"); + } }