From c7a7b4ee6228d12663c326c2986de30fb3594fdd Mon Sep 17 00:00:00 2001
From: stepan <stepan.sindelar@oracle.com>
Date: Thu, 19 Apr 2018 14:49:44 +0200
Subject: [PATCH] Do not allow empty in '...' for most builtins

This adds mustBeValidVarArgs method to the cast pipeline
---
 .../truffle/r/nodes/builtin/base/Combine.java |  1 +
 .../r/nodes/builtin/base/ListBuiltin.java     |  3 +-
 .../truffle/r/nodes/builtin/base/Order.java   |  3 +-
 .../truffle/r/nodes/builtin/base/Repeat.java  |  2 +
 .../truffle/r/nodes/casts/MarkLookup.java     |  6 ++
 .../r/nodes/casts/ResultTypesAnalyser.java    |  8 ++
 .../r/nodes/casts/SamplesCollector.java       |  8 ++
 .../truffle/r/nodes/builtin/CastBuilder.java  | 11 +++
 .../truffle/r/nodes/builtin/casts/Filter.java | 11 +++
 .../builtin/casts/PipelineToCastNode.java     | 11 +++
 .../analysis/ForwardedValuesAnalyser.java     |  6 ++
 .../casts/fluent/InitialPhaseBuilder.java     | 10 +++
 .../truffle/r/nodes/unary/CastNode.java       |  3 +-
 .../r/nodes/unary/RVarArgsFilterNode.java     | 77 +++++++++++++++++++
 .../truffle/r/test/ExpectedTestOutput.test    | 16 ++++
 .../r/test/builtins/TestBuiltin_c.java        |  2 +
 .../r/test/builtins/TestBuiltin_list.java     |  4 +-
 .../r/test/builtins/TestBuiltin_rep.java      |  5 +-
 .../r/test/builtins/TestBuiltin_switch.java   |  4 +-
 19 files changed, 185 insertions(+), 6 deletions(-)
 create mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/RVarArgsFilterNode.java

diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
index 7d0f07f953..d46dfb479d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
@@ -110,6 +110,7 @@ public abstract class Combine extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(Combine.class);
+        casts.arg("...").mustBeValidVarArgs();
         casts.arg("recursive").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java
index dc2095ae87..aa1452b747 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java
@@ -56,7 +56,8 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 {
     @CompilationFinal private RStringVector suppliedSignatureArgNames;
 
     static {
-        Casts.noCasts(ListBuiltin.class);
+        Casts casts = new Casts(ListBuiltin.class);
+        casts.arg("...").allowMissing().mustBeValidVarArgs();
     }
 
     /**
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java
index c188ea4ce0..21a515a379 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -157,6 +157,7 @@ public abstract class Order extends RPrecedenceBuiltinNode {
 
     static {
         Casts casts = new Casts(Order.class);
+        casts.arg("...").mustBeValidVarArgs();
         casts.arg("na.last").mustBe(numericValue(), INVALID_LOGICAL, "na.last").asLogicalVector().findFirst();
         casts.arg("decreasing").defaultError(INVALID_LOGICAL, "decreasing").mustBe(numericValue()).asLogicalVector().findFirst().mustNotBeNA().map(toBoolean());
     }
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 c94d04d820..5cee144e27 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
@@ -122,6 +122,8 @@ public abstract class Repeat extends RBuiltinNode.Arg2 {
         ARG_IDX_LENGHT_OUT = 1;
         ARG_IDX_EACH = 2;
         FORMALS = FormalArguments.createForBuiltin(new Object[]{1, RRuntime.INT_NA, 1}, signature);
+
+        // Note: repeat is happy with empty arguments in varagrs
     }
 
     @Child private FastRInternalRepeat internalNode = FastRInternalRepeatNodeGen.create();
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/MarkLookup.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/MarkLookup.java
index 85f025e652..863eb2ddad 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/MarkLookup.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/MarkLookup.java
@@ -39,6 +39,7 @@ import com.oracle.truffle.r.nodes.builtin.casts.Filter.NotFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.NullFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.RTypeFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.RVarArgsFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.TypeFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper;
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapByteToBoolean;
@@ -205,6 +206,11 @@ public final class MarkLookup implements PipelineStepVisitor<Map<String, Object>
         return visitFilter(filter, foundMarks);
     }
 
+    @Override
+    public Map<String, Object> visit(RVarArgsFilter filter, Map<String, Object> foundMarks) {
+        return visitFilter(filter, foundMarks);
+    }
+
     // Mapper visitor
 
     public Map<String, Object> visitMapper(Mapper<?, ?> mapper, Map<String, Object> foundMarks) {
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/ResultTypesAnalyser.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/ResultTypesAnalyser.java
index e383c823b2..b4a80787b4 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/ResultTypesAnalyser.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/ResultTypesAnalyser.java
@@ -48,6 +48,7 @@ import com.oracle.truffle.r.nodes.builtin.casts.Filter.NotFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.NullFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.RTypeFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.RVarArgsFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.TypeFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapByteToBoolean;
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapDoubleToInt;
@@ -78,6 +79,7 @@ import com.oracle.truffle.r.nodes.unary.CastToAttributableNode;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
+import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDouble;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -347,6 +349,12 @@ public class ResultTypesAnalyser extends ExecutionPathVisitor<TypeExpr> implemen
         return previous.lower(filter).and(NOT_NULL_NOT_MISSING);
     }
 
+    @Override
+    public TypeExpr visit(RVarArgsFilter filter, TypeExpr previous) {
+        TypeExpr res = atom(RArgsValuesAndNames.class);
+        return res;
+    }
+
     @Override
     public TypeExpr visit(DoubleFilter filter, TypeExpr previous) {
         return previous.lower(filter);
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/SamplesCollector.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/SamplesCollector.java
index 7b664e03c0..ab5c7b59ec 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/SamplesCollector.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/SamplesCollector.java
@@ -45,6 +45,7 @@ import com.oracle.truffle.r.nodes.builtin.casts.Filter.NotFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.NullFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.RTypeFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.RVarArgsFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.TypeFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapByteToBoolean;
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapDoubleToInt;
@@ -298,6 +299,13 @@ public class SamplesCollector extends ExecutionPathVisitor<Consumer<Object>>
         };
     }
 
+    @Override
+    public Consumer<Object> visit(RVarArgsFilter filter, Consumer<Object> previous) {
+        return s -> {
+            previous.accept(s);
+        };
+    }
+
     @Override
     public Consumer<Object> visit(DoubleFilter filter, Consumer<Object> previous) {
         return s -> {
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 195f31226a..a28127dffd 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
@@ -63,6 +63,7 @@ import com.oracle.truffle.r.runtime.RInternalError;
 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.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -697,6 +698,16 @@ public final class CastBuilder {
             return new TypeFilter<>(Object.class);
         }
 
+        /**
+         * Valid {@link RArgsValuesAndNames} do not contain
+         * {@link com.oracle.truffle.r.runtime.data.REmpty} values.
+         */
+        @SuppressWarnings({"rawtypes", "unchecked"})
+        public static Filter<Object, RArgsValuesAndNames> validVarArgs() {
+            Filter f = integerValue().or(doubleValue()).or(logicalValue());
+            return f;
+        }
+
         @SuppressWarnings({"rawtypes", "unchecked"})
         public static Filter<Object, RAbstractVector> numericValue() {
             Filter f = integerValue().or(doubleValue()).or(logicalValue());
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/Filter.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/Filter.java
index 81f2bd6d2e..e5f12c84aa 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/Filter.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/Filter.java
@@ -28,6 +28,7 @@ import com.oracle.truffle.r.nodes.builtin.ArgumentFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.FilterStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapStep;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
@@ -82,6 +83,8 @@ public abstract class Filter<T, R extends T> {
         D visit(NullFilter filter, D previous);
 
         D visit(MissingFilter filter, D previous);
+
+        D visit(RVarArgsFilter filter, D previous);
     }
 
     /**
@@ -434,6 +437,14 @@ public abstract class Filter<T, R extends T> {
         }
     }
 
+    public static final class RVarArgsFilter extends Filter<Object, RArgsValuesAndNames> {
+
+        @Override
+        public <D> D accept(FilterVisitor<D> visitor, D previous) {
+            return visitor.visit(this, previous);
+        }
+    }
+
     public abstract static class DoubleFilter extends Filter<Double, Double> {
 
         public static final DoubleFilter IS_FINITE = new DoubleFilter() {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java
index 7c93ac2ac8..97f0d2b7d2 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java
@@ -46,6 +46,7 @@ import com.oracle.truffle.r.nodes.builtin.casts.Filter.NotFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.NullFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.RTypeFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.RVarArgsFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.ResultForArg;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.TypeFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapByteToBoolean;
@@ -82,6 +83,7 @@ import com.oracle.truffle.r.nodes.unary.FilterNode;
 import com.oracle.truffle.r.nodes.unary.FindFirstNodeGen;
 import com.oracle.truffle.r.nodes.unary.MapNode;
 import com.oracle.truffle.r.nodes.unary.NonNANodeGen;
+import com.oracle.truffle.r.nodes.unary.RVarArgsFilterNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -197,6 +199,9 @@ public final class PipelineToCastNode {
 
         @Override
         public CastNode visit(FilterStep<?, ?> step, CastNode previous) {
+            if (step.getFilter() instanceof RVarArgsFilter) {
+                return RVarArgsFilterNode.create();
+            }
             @SuppressWarnings("unchecked")
             ArgumentFilter<Object, Object> filter = (ArgumentFilter<Object, Object>) ArgumentFilterFactoryImpl.INSTANCE.createFilter(step.getFilter());
             MessageData msg = getDefaultIfNull(step.getMessage(), step.isWarning());
@@ -260,6 +265,7 @@ public final class PipelineToCastNode {
 
         @Override
         public CastNode visit(MapIfStep<?, ?> step, CastNode previous) {
+            assert !(step.getFilter() instanceof RVarArgsFilter) : "mapIf not yet implemented for RVarArgsFilter";
             @SuppressWarnings("unchecked")
             ArgumentFilter<Object, Object> condition = (ArgumentFilter<Object, Object>) ArgumentFilterFactoryImpl.INSTANCE.createFilter(step.getFilter());
             CastNode trueCastNode = PipelineToCastNode.convert(null, step.getTrueBranch(), this);
@@ -410,6 +416,11 @@ public final class PipelineToCastNode {
             return filter.acceptOperation(this, null);
         }
 
+        @Override
+        public ArgumentFilter<?, ?> visit(RVarArgsFilter filter, ArgumentFilter<?, ?> previous) {
+            throw RInternalError.shouldNotReachHere("This filter should be handled separately as it has its own node.");
+        }
+
         @Override
         public ArgumentFilter<?, ?> visit(DoubleFilter filter, ArgumentFilter<?, ?> previous) {
             return filter.acceptOperation(this, null);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardedValuesAnalyser.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardedValuesAnalyser.java
index 631c6d8685..5d06fa101b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardedValuesAnalyser.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardedValuesAnalyser.java
@@ -42,6 +42,7 @@ import com.oracle.truffle.r.nodes.builtin.casts.Filter.NotFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.NullFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.RTypeFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.RVarArgsFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.TypeFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper;
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapByteToBoolean;
@@ -263,6 +264,11 @@ public final class ForwardedValuesAnalyser implements PipelineStepVisitor<Forwar
                 return new ForwardingAnalysisResult().blockAll();
             }
 
+            @Override
+            public ForwardingAnalysisResult visit(RVarArgsFilter filter, ForwardingAnalysisResult previous) {
+                return new ForwardingAnalysisResult().blockAll();
+            }
+
             @Override
             public ForwardingAnalysisResult visit(DoubleFilter filter, @SuppressWarnings("hiding") ForwardingAnalysisResult previous) {
                 return new ForwardingAnalysisResult().blockAll().setForwardedType(RType.Double, UNKNOWN);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java
index d5c603ad89..49514f0a33 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java
@@ -24,9 +24,11 @@ package com.oracle.truffle.r.nodes.builtin.casts.fluent;
 
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.RVarArgsFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RComplex;
@@ -65,6 +67,14 @@ public class InitialPhaseBuilder<T> extends ArgCastBuilder<T, InitialPhaseBuilde
         return (InitialPhaseBuilder<S>) this;
     }
 
+    /**
+     * Valid {@link com.oracle.truffle.r.runtime.data.RArgsValuesAndNames} does not contain any
+     * {@link com.oracle.truffle.r.runtime.data.REmpty} values.
+     */
+    public void mustBeValidVarArgs() {
+        pipelineBuilder().appendMustBeStep(new RVarArgsFilter(), Message.INVALID_ARG_TYPE, new Object[0]);
+    }
+
     public <S extends T> InitialPhaseBuilder<S> mustBe(Class<S> cls) {
         mustBe(Predef.instanceOf(cls));
         return (InitialPhaseBuilder<S>) this;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastNode.java
index 76a270746e..5f3ea354eb 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastNode.java
@@ -26,6 +26,7 @@ import java.util.Arrays;
 import java.util.function.Function;
 
 import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.builtin.casts.MessageData;
 import com.oracle.truffle.r.runtime.RError;
@@ -36,7 +37,7 @@ import com.oracle.truffle.r.runtime.RError;
  */
 public abstract class CastNode extends UnaryNode {
 
-    private static boolean isTesting = false;
+    @CompilationFinal private static boolean isTesting = false;
     private static String lastWarning;
 
     private final ValueProfile classProfile = ValueProfile.createClassProfile();
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/RVarArgsFilterNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/RVarArgsFilterNode.java
new file mode 100644
index 0000000000..8f495e7951
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/RVarArgsFilterNode.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 3 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 3 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.unary;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.nodes.ExplodeLoop;
+import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.nodes.builtin.casts.MessageData;
+import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
+import com.oracle.truffle.r.runtime.data.REmpty;
+
+public abstract class RVarArgsFilterNode extends CastNode {
+
+    public static RVarArgsFilterNode create() {
+        return RVarArgsFilterNodeGen.create();
+    }
+
+    @ExplodeLoop
+    @Specialization(guards = "args.getLength() == cachedLen")
+    protected Object cached(RArgsValuesAndNames args,
+                    @Cached("create()") BranchProfile errorProfile,
+                    @Cached("args.getLength()") int cachedLen) {
+        Object[] vals = args.getArguments();
+        for (int i = 0; i < cachedLen; i++) {
+            if (vals[i] == REmpty.instance) {
+                errorProfile.enter();
+                throw handleArgumentError(args, new MessageData(Message.ARGUMENT_EMPTY, i + 1));
+            }
+        }
+        return args;
+    }
+
+    @Specialization(replaces = "cached")
+    protected Object generic(RArgsValuesAndNames args,
+                    @Cached("create()") BranchProfile errorProfile) {
+        Object[] vals = args.getArguments();
+        for (int i = 0; i < vals.length; i++) {
+            if (vals[i] == REmpty.instance) {
+                errorProfile.enter();
+                throw handleArgumentError(args, new MessageData(Message.ARGUMENT_EMPTY, i));
+            }
+        }
+        return args;
+    }
+
+    @Fallback
+    @TruffleBoundary
+    protected Object others(Object obj) {
+        String actualCls = obj == null ? "null" : obj.getClass().getSimpleName();
+        throw RInternalError.shouldNotReachHere(String.format("RVarArgsFilter should be used only for %s, but used for %s", RArgsValuesAndNames.class.getSimpleName(), actualCls));
+    }
+}
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 a589460550..5ef348d3f9 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
@@ -11726,6 +11726,10 @@ NULL
 Warning message:
 In body(argv[[1]]) : argument is not a function
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testCombine#
+#c(1,2,)
+Error in c(1, 2, ) : argument 3 is empty
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testCombine#
 #c(as.expression(1))
 expression(1)
@@ -35570,6 +35574,10 @@ numeric(0)
 Warning message:
 In do.call("lgamma", argv) : value out of range in 'lgamma'
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_list.testList#
+#list(1,2,3,)
+Error in list(1, 2, 3, ) : argument 4 is empty
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_list.testList#
 #{ list(1, b=2) }
 [[1]]
@@ -53097,6 +53105,10 @@ attr(,"useBytes")
  [1] " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
 [20] " "
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep#Output.IgnoreWarningMessage#
+#rep(3, 4,)
+[1] 3 3 3 3
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep#
 #rep(x<-42)
 [1] 42
@@ -74707,6 +74719,10 @@ In matrix(7:1, nrow = 5) :
 [4,]
 [5,]
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_switch.testSwitch#Ignored.Unimplemented#
+#switch('q', a=42,)
+Error: argument is missing, with no default
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_switch.testSwitch#
 #{ a <- NULL ; switch(mode(a), NULL="naught") }
 [1] "naught"
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java
index 974a0d5f7b..b28588066d 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java
@@ -554,6 +554,8 @@ public class TestBuiltin_c extends TestBase {
         assertEval("c(as.symbol(1), as.symbol(1))");
         assertEval("{ setClass('foo', representation(bar = 'ANY')); c(new('foo', bar=1)) }");
         assertEval("{ setClass('foo', representation(bar = 'ANY')); c(new('foo', bar=1), new('foo', bar=1)) }");
+
+        assertEval("c(1,2,)");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java
index 7b5ffe64de..2183c7b39e 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -366,5 +366,7 @@ public class TestBuiltin_list extends TestBase {
         assertEval("{ x<-list(y=1, 2);  c(42, a=x) }");
         assertEval("{ x<-list(y=1, 2);  c(a=x, c(z=7,42)) }");
         assertEval("{ x<-list(y=1, 2);  c(a=x, c(y=7,z=42)) }");
+
+        assertEval("list(1,2,3,)");
     }
 }
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 01f86871e8..a6aaf4e375 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
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -241,5 +241,8 @@ public class TestBuiltin_rep extends TestBase {
         assertEval("{ rep(paste0('hello', 1:10), 1:10) }");
 
         assertEval("rep(' ', 20L, collapse = ' ')");
+
+        // FIXME: should not print the warnings if empty args occur in '...'
+        assertEval(Output.IgnoreWarningMessage, "rep(3, 4,)");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_switch.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_switch.java
index 823c928e5a..299276200c 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_switch.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_switch.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -49,6 +49,8 @@ public class TestBuiltin_switch extends TestBase {
         assertEval("{ a <- NULL ; switch(mode(a), NULL=) }");
         assertEval(Output.IgnoreErrorContext, "{ x <- \"!\"; v <- switch(x, v77, \"<=\" =, \"<\" =, \">\" = 99, v55)}");
         assertEval("{ x <- \"!\"; v <- switch(x, \"\"=v77, \"<=\" =, \"<\" =, \">\" = 99, v55)}");
+        // FIXME: swicth does not check for REmpty
+        assertEval(Ignored.Unimplemented, "switch('q', a=42,)");
     }
 
     @Test
-- 
GitLab