diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java index 5cee144e27517e118dbfadbaca305c550240a80f..bd8d2c4312705d43ab68c229050dd42a5d6c802c 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java @@ -58,6 +58,7 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RAttributesLayout; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RMissing; +import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RTypes; import com.oracle.truffle.r.runtime.data.RVector; @@ -99,7 +100,7 @@ public abstract class Repeat extends RBuiltinNode.Arg2 { static { Casts casts = new Casts(Repeat.class); - casts.arg("x").mustBe(abstractVectorValue(), RError.Message.ATTEMPT_TO_REPLICATE, typeName()); + casts.arg("x").allowNull().mustBe(abstractVectorValue(), RError.Message.ATTEMPT_TO_REPLICATE, typeName()); // prepare cast pipeline nodes for vararg matching PB_TIMES = new PipelineBuilder("times"); @@ -137,6 +138,11 @@ public abstract class Repeat extends RBuiltinNode.Arg2 { return new Object[]{RMissing.instance, RArgsValuesAndNames.EMPTY}; } + @Specialization + protected RNull repeatNull(@SuppressWarnings("unused") RNull x, @SuppressWarnings("unused") RArgsValuesAndNames args) { + return RNull.instance; + } + @Specialization protected Object repeat(VirtualFrame frame, RAbstractVector x, RArgsValuesAndNames args) { RArgsValuesAndNames margs = prepareArgs.execute(args, null); @@ -238,7 +244,7 @@ public abstract class Repeat extends RBuiltinNode.Arg2 { * Extend or truncate the vector to a specified length. */ private static RVector<?> handleLengthOut(RAbstractVector x, int lengthOut) { - return x.copyResized(lengthOut, false); + return x.copyResized(lengthOut, x.getLength() == 0); } /** diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java index a5498304f6410c181058c235544dca84fafee8d0..7e9bbe7ebd088a626acd839c00879af200cde77d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java @@ -153,16 +153,18 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract private double[] copyResizedData(int size, boolean fillNA) { int csize = size << 1; - double[] newData = Arrays.copyOf(getReadonlyData(), csize); - if (csize > this.getLength()) { + double[] localData = getReadonlyData(); + double[] newData = Arrays.copyOf(localData, csize); + if (csize > localData.length) { if (fillNA) { - for (int i = data.length; i < size; i++) { + for (int i = localData.length; i < csize; i++) { newData[i] = RRuntime.DOUBLE_NA; } } else { - for (int i = data.length, j = 0; i <= csize - 2; i += 2, j = Utils.incMod(j + 1, data.length)) { - newData[i] = data[j]; - newData[i + 1] = data[j + 1]; + assert localData.length > 0 : "cannot call resize on empty vector if fillNA == false"; + for (int i = localData.length, j = 0; i <= csize - 2; i += 2, j = Utils.incMod(j + 1, localData.length)) { + newData[i] = localData[j]; + newData[i + 1] = localData[j + 1]; } } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java index c591f5f6b4ba0e831678fed17bf33a6cee4346f2..893b7512a9b1a8da5b8c78ca579394226ee1b02c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java @@ -178,6 +178,7 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD newData[i] = RRuntime.DOUBLE_NA; } } else { + assert oldData.length > 0 : "cannot call resize on empty vector if fillNA == false"; for (int i = oldDataLength, j = 0; i < newData.length; ++i, j = Utils.incMod(j, oldDataLength)) { newData[i] = oldData[j]; } @@ -187,8 +188,9 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD } private double[] copyResizedData(int size, boolean fillNA) { - double[] newData = Arrays.copyOf(getReadonlyData(), size); - return resizeData(newData, this.data, this.getLength(), fillNA); + double[] localData = getReadonlyData(); + double[] newData = Arrays.copyOf(localData, size); + return resizeData(newData, localData, localData.length, fillNA); } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java index d3552c1fdb6010c9d0d6ce8ac49ed02c7e3a0519..20438aaa0d152fada24d795ebac07e4a93fd8c68 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java @@ -181,6 +181,7 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect newData[i] = RRuntime.INT_NA; } } else { + assert oldDataLength > 0 : "cannot call resize on empty vector if fillNA == false"; for (int i = oldDataLength, j = 0; i < newData.length; ++i, j = Utils.incMod(j, oldDataLength)) { newData[i] = oldData[j]; } @@ -190,8 +191,9 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect } private int[] copyResizedData(int size, boolean fillNA) { - int[] newData = Arrays.copyOf(getReadonlyData(), size); - return resizeData(newData, this.data, this.getLength(), fillNA); + int[] localData = getReadonlyData(); + int[] newData = Arrays.copyOf(localData, size); + return resizeData(newData, localData, localData.length, fillNA); } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java index 3c59ac2adc4ee7ee83e87823fa66990af0df81bf..ad9adb0365c9ea5c5b8b960e847e6dbfd19a6a7d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java @@ -169,6 +169,7 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi newData[i] = RNull.instance; } } else { + assert oldDataLength > 0 : "cannot call resize on empty vector if fillNA == false"; for (int i = oldData.length, j = 0; i < newData.length; ++i, j = Utils.incMod(j, oldData.length)) { newData[i] = oldData[j]; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java index c5f4390abf7e3177f4427b1544574e0ab1a01ae6..483fdec59880d2e59044b1fb00586b952a26655a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java @@ -154,15 +154,17 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo } private byte[] copyResizedData(int size, boolean fillNA) { - byte[] newData = Arrays.copyOf(getReadonlyData(), size); - if (size > this.getLength()) { + byte[] localData = getReadonlyData(); + byte[] newData = Arrays.copyOf(localData, size); + if (size > localData.length) { if (fillNA) { - for (int i = data.length; i < size; i++) { + for (int i = localData.length; i < size; i++) { newData[i] = RRuntime.LOGICAL_NA; } } else { - for (int i = data.length, j = 0; i < size; ++i, j = Utils.incMod(j, data.length)) { - newData[i] = data[j]; + assert localData.length > 0 : "cannot call resize on empty vector if fillNA == false"; + for (int i = localData.length, j = 0; i < size; ++i, j = Utils.incMod(j, localData.length)) { + newData[i] = localData[j]; } } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java index 49ef57251f49cf163402d23c2620d96f8debb611..2edd0d69e979dff5c37a4e4e69a2fa6626a1e8b0 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java @@ -155,10 +155,12 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec } private byte[] copyResizedData(int size, boolean fillNA) { - byte[] newData = Arrays.copyOf(getReadonlyData(), size); + byte[] localData = getReadonlyData(); + byte[] newData = Arrays.copyOf(localData, size); if (!fillNA) { + assert localData.length > 0 : "cannot call resize on empty vector if fillNA == false"; // NA is 00 for raw - for (int i = data.length, j = 0; i < size; ++i, j = Utils.incMod(j, data.length)) { + for (int i = localData.length, j = 0; i < size; ++i, j = Utils.incMod(j, localData.length)) { newData[i] = data[j]; } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java index eeb21176719f2f2b16fb82d76dbc054b9eee9f80..c73b9f689e45aed7df603ced95c7284384794cfa 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java @@ -146,15 +146,17 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS } private String[] copyResizedData(int size, String fill) { - String[] newData = Arrays.copyOf(data, size); - if (size > this.getLength()) { + String[] localData = getReadonlyData(); + String[] newData = Arrays.copyOf(localData, size); + if (size > localData.length) { if (fill != null) { - for (int i = data.length; i < size; i++) { + for (int i = localData.length; i < size; i++) { newData[i] = fill; } } else { - for (int i = data.length, j = 0; i < size; ++i, j = Utils.incMod(j, data.length)) { - newData[i] = data[j]; + assert localData.length > 0 : "cannot call resize on empty vector if fillNA == false"; + for (int i = localData.length, j = 0; i < size; ++i, j = Utils.incMod(j, localData.length)) { + newData[i] = localData[j]; } } } 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 8027948599d7c1970107e0814a172e353b2d0023..3b787d3e951f582f2b95faf4ad856f155322c935 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 @@ -53121,6 +53121,39 @@ attr(,"useBytes") #rep(3, 4,) [1] 3 3 3 3 +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(NULL) +NULL + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(character(), length.out=2) +[1] NA NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(complex(), length.out=2) +[1] NA NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(list(), length.out=2) +[[1]] +NULL + +[[2]] +NULL + + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(numeric(), length.out=2) +[1] NA NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(numeric(), times=3) +numeric(0) + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(raw(), length.out=2) +[1] 00 00 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# #rep(x<-42) [1] 42 diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.java index a6aaf4e37581c2dbc96e97f65b52c3146241e47f..028788e9f3a0467d954afc7e6ec69a9637f4ac68 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.java @@ -244,5 +244,15 @@ public class TestBuiltin_rep extends TestBase { // FIXME: should not print the warnings if empty args occur in '...' assertEval(Output.IgnoreWarningMessage, "rep(3, 4,)"); + + assertEval("rep(numeric(), length.out=2)"); + assertEval("rep(character(), length.out=2)"); + assertEval("rep(raw(), length.out=2)"); + assertEval("rep(complex(), length.out=2)"); + assertEval("rep(list(), length.out=2)"); + + assertEval("rep(numeric(), times=3)"); + + assertEval("rep(NULL)"); } }