diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java index 6383859deaab3e59577068cda6b109e6c62c2447..c4ef69e257b504728928dec2d04497c9b409c195 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java @@ -182,7 +182,6 @@ public abstract class VApply extends RBuiltinNode.Arg4 { boolean applyResultZeroLength = zeroLengthProfile.profile(applyResult.length == 0); naCheck.enable(true); - // TODO check funValueLen against length of result if (funValueVec instanceof RAbstractIntVector) { int[] data = applyResultZeroLength ? new int[0] : convertIntVector(applyResult, funValueVecLen); result = RDataFactory.createIntVector(data, naCheck.neverSeenNA()); @@ -247,11 +246,19 @@ public abstract class VApply extends RBuiltinNode.Arg4 { return result; } + private static void checkValueLength(RAbstractVector v, int idx, int expectedLength) { + int actualLength = v.getLength(); + if (actualLength != expectedLength) { + throw RError.error(RError.SHOW_CALLER, RError.Message.VALUES_MUST_BE_LENGTH, expectedLength, idx + 1, actualLength); + } + } + private double[] convertDoubleVector(Object[] values, int len) { double[] newArray = new double[values.length * len]; int ind = 0; for (int i = 0; i < values.length; i++) { RAbstractDoubleVector v = (RAbstractDoubleVector) castDouble(values[i]); + checkValueLength(v, i, len); for (int j = 0; j < v.getLength(); j++) { double val = v.getDataAt(j); naCheck.check(val); @@ -266,6 +273,7 @@ public abstract class VApply extends RBuiltinNode.Arg4 { int ind = 0; for (int i = 0; i < values.length; i++) { RAbstractIntVector v = (RAbstractIntVector) castInteger(values[i]); + checkValueLength(v, i, len); for (int j = 0; j < v.getLength(); j++) { int val = v.getDataAt(j); naCheck.check(val); @@ -280,6 +288,7 @@ public abstract class VApply extends RBuiltinNode.Arg4 { int ind = 0; for (int i = 0; i < values.length; i++) { RAbstractLogicalVector v = (RAbstractLogicalVector) castLogical(values[i]); + checkValueLength(v, i, len); for (int j = 0; j < v.getLength(); j++) { byte val = v.getDataAt(j); naCheck.check(val); @@ -294,6 +303,7 @@ public abstract class VApply extends RBuiltinNode.Arg4 { int ind = 0; for (int i = 0; i < values.length; i++) { RAbstractStringVector v = (RAbstractStringVector) castString(values[i]); + checkValueLength(v, i, len); for (int j = 0; j < v.getLength(); j++) { String val = v.getDataAt(j); naCheck.check(val); @@ -308,6 +318,7 @@ public abstract class VApply extends RBuiltinNode.Arg4 { int ind = 0; for (int i = 0; i < values.length; i++) { RAbstractComplexVector v = (RAbstractComplexVector) castComplex(values[i]); + checkValueLength(v, i, len); for (int j = 0; j < v.getLength(); j++) { RComplex val = v.getDataAt(j); naCheck.check(val); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java index 8e0f4da8cea9e117c665ca60c6e8aaea3b68c409..c0a021efa81949f83664786c0f8bb8d7fac9ff8f 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java @@ -896,7 +896,8 @@ public final class RError extends RuntimeException implements TruffleException { OBJECT_SIZE_ESTIMATE("The object size is only estimated."), REPLACING_IN_NON_CHAR_OBJ("replacing substrings in a non-character object"), FILE_NOT_FOUND_IN_ZIP("requested file not found in the zip file"), - LIST_NO_VALID_NAMES("list argument has no valid names"); + LIST_NO_VALID_NAMES("list argument has no valid names"), + VALUES_MUST_BE_LENGTH("values must be length %s,\n but FUN(X[[%d]]) result is length %s"); public final String message; final boolean hasArgs; 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 dc9999464e0b320d741dc95909a1792f791257d5..d33d3e838aa72399dd28e6ea60cf78878143dcde 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 @@ -73636,6 +73636,23 @@ Error in utf8ToInt(numeric(0)) : #{ iv <- integer(1); iv[[1]] = 1L; vapply(c(1L, 2L, 3L, 4L), function(x) x+5L, iv) } [1] 6 7 8 9 +##com.oracle.truffle.r.test.builtins.TestBuiltin_vapply.testVapply#Output.IgnoreErrorContext# +#{ vapply(1:3, function(x) rep(1, x), 1); } +Error in vapply(1:3, function(x) rep(1, x), 1) : values must be length 1, + but FUN(X[[2]]) result is length 2 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_vapply.testVapply#Output.IgnoreErrorContext# +#{ vapply(1:3, function(x) rep(1, x), 1:3); } +Error in vapply(1:3, function(x) rep(1, x), 1:3) : + values must be length 3, + but FUN(X[[1]]) result is length 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_vapply.testVapply#Output.IgnoreErrorContext# +#{ vapply(1:3, function(x) rep(1, x), 1L:3L); } +Error in vapply(1:3, function(x) rep(1, x), 1L:3L) : + values must be length 3, + but FUN(X[[1]]) result is length 1 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_vapply.testVapply# #{ vapply(c("foo", "bar"), 42, c(TRUE)) } Error in match.fun(FUN) : '42' is not a function, character or symbol diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_vapply.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_vapply.java index c171773a5fce99766a9cde7e06727872a7d4e1a1..69b4df6cae9b6e07aea08cb05c4a8b3944c89ec5 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_vapply.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_vapply.java @@ -46,6 +46,10 @@ public class TestBuiltin_vapply extends TestBase { assertEval("{ vapply(quote(a), function(x) 42, 1); }"); assertEval(Output.IgnoreErrorContext, "{ vapply(quote(a), function(x) quote(b), quote(a)); }"); assertEval("{ vapply(c(1,2,3), 42, 1); }"); + + assertEval(Output.IgnoreErrorContext, "{ vapply(1:3, function(x) rep(1, x), 1); }"); + assertEval(Output.IgnoreErrorContext, "{ vapply(1:3, function(x) rep(1, x), 1:3); }"); + assertEval(Output.IgnoreErrorContext, "{ vapply(1:3, function(x) rep(1, x), 1L:3L); }"); } @Test