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 e9748c82908fd0936ef94148042354a528f0b0cc..58653d31ac1260cf5795ed598a7cc9d339a60374 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
@@ -41,6 +41,7 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.nodes.Node;
@@ -78,6 +79,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
+@ImportStatic(RRuntime.class)
 @RBuiltin(name = "c", kind = PRIMITIVE, parameterNames = {"...", "recursive"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
 public abstract class Combine extends RBuiltinNode.Arg2 {
 
@@ -110,7 +112,7 @@ public abstract class Combine extends RBuiltinNode.Arg2 {
     public abstract Object executeCombine(Object value, Object recursive);
 
     protected boolean isSimpleArguments(RArgsValuesAndNames args) {
-        return !signatureHasNames(args.getSignature()) && args.getLength() == 1 && !(args.getArgument(0) instanceof RAbstractVector);
+        return !signatureHasNames(args.getSignature()) && args.getLength() == 1 && !(args.getArgument(0) instanceof RAbstractVector) && !RRuntime.isForeignObject(args.getArgument(0));
     }
 
     @Specialization(guards = {"isSimpleArguments(args)", "!recursive"})
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java
index 4049261a8a263e7929f019d6c73a1d24f5c99bc4..11cbc9ac724d29fb42f9bf2cc27bff32a31d5ed2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java
@@ -765,7 +765,7 @@ public class FastRInterop {
 
         static {
             Casts casts = new Casts(FromForeignArray.class);
-            casts.arg("array").mustNotBeMissing();
+            casts.arg("array").castForeignObjects(false).mustNotBeMissing();
         }
 
         private final ConditionProfile isArrayProfile = ConditionProfile.createBinaryProfile();
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/castsTests/CastBuilderTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/castsTests/CastBuilderTest.java
index ad4f0b46c876189de0c9944a81c4a17bf13b92e4..817a66144fcecafb1cae808b9baca46ef9f8692a 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/castsTests/CastBuilderTest.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/castsTests/CastBuilderTest.java
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.nodes.castsTests;
 
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.java.JavaInterop;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.anyValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asBoolean;
@@ -102,12 +104,15 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 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.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.REnvironment.NewEnv;
 import com.oracle.truffle.r.test.generate.FastRSession;
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * Tests the cast pipelines and also that the samples generation process matches the intended
@@ -903,6 +908,30 @@ public class CastBuilderTest {
         assertCastFail("abc");
     }
 
+    @Test
+    public void testCastForeignArray() {
+        arg.mustBe(integerValue());
+        int[] array = new int[]{1, 2, 3};
+        Object value = cast(JavaInterop.asTruffleObject(array));
+        assertTrue(value instanceof RAbstractIntVector);
+    }
+
+    @Test
+    public void testCastJavaIterable() {
+        arg.mustBe(integerValue());
+        List<Integer> list = Arrays.asList(1, 2, 3);
+        Object value = cast(JavaInterop.asTruffleObject(list));
+        assertTrue(value instanceof RAbstractIntVector);
+    }
+
+    @Test
+    public void testCastForeignObjectDisabled() {
+        arg.castForeignObjects(false).mustBe(missingValue().not());
+        TruffleObject obj = JavaInterop.asTruffleObject(new int[]{1, 2, 3});
+        Object value = cast(obj);
+        assertTrue(value == obj);
+    }
+
     /**
      * Casts given object using the configured pipeline in {@link #arg}.
      */
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/PipelineToCastNodeTests.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/PipelineToCastNodeTests.java
index 444a877bf6a11d8a738e66673aebfcae3bd9d489..076b9cce21dc530e40ba989bd77d7d2cdffc1bd2 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/PipelineToCastNodeTests.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/PipelineToCastNodeTests.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.test;
 
+import com.oracle.truffle.r.nodes.builtin.casts.CastForeignNode;
 import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assert.assertEquals;
 
@@ -52,27 +53,59 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 public class PipelineToCastNodeTests {
     @Test
     public void asLogicalVector() {
-        assertTrue(createPipeline(new CoercionStep<>(RType.Logical, false)) instanceof CastLogicalBaseNode);
+        // without first cast of foreign objects
+        CastNode pipeline = createPipeline(new CoercionStep<>(RType.Logical, false), false);
+        assertTrue(pipeline instanceof CastLogicalBaseNode);
+
+        // with first cast of foreign objects
+        pipeline = createPipeline(new CoercionStep<>(RType.Logical, false), true);
+        assertChainedCast(pipeline, CastForeignNode.class, CastLogicalBaseNode.class);
     }
 
     @Test
     public void asStringVectorFindFirst() {
-        assertChainedCast(createPipeline(new CoercionStep<>(RType.Character, false).setNext(new FindFirstStep<>("hello", String.class, null))), CastStringBaseNode.class, FindFirstNode.class);
-        FindFirstNode findFirst = (FindFirstNode) ((ChainedCastNode) createPipeline(
-                        new CoercionStep<>(RType.Character, false).setNext(new FindFirstStep<>("hello", String.class, null)))).getSecondCast();
+        PipelineStep<?, ?> steps = new CoercionStep<>(RType.Character, false).setNext(new FindFirstStep<>("hello", String.class, null));
+
+        // without first cast of foreign objects
+        CastNode pipeline = createPipeline(steps, false);
+        assertChainedCast(pipeline, CastStringBaseNode.class, FindFirstNode.class);
+
+        FindFirstNode findFirst = (FindFirstNode) ((ChainedCastNode) pipeline).getSecondCast();
         assertEquals("hello", findFirst.getDefaultValue());
+
+        // with first cast of foreign objects
+        pipeline = createPipeline(steps, true);
+        assertChainedCast(pipeline, ChainedCastNode.class, FindFirstNode.class);
+
+        CastNode next = ((ChainedCastNode) pipeline).getFirstCast();
+        assertChainedCast(next, CastForeignNode.class, CastStringBaseNode.class);
     }
 
     @Test
     public void mustBeREnvironmentAsIntegerVectorFindFirst() {
-        assertChainedCast(createPipeline(new FilterStep<>(new TypeFilter<>(REnvironment.class), null, false).setNext(
-                        new CoercionStep<>(RType.Integer, false).setNext(new FindFirstStep<>("hello", String.class, null)))), ChainedCastNode.class, FindFirstNode.class);
-        CastNode next = ((ChainedCastNode) createPipeline(new FilterStep<>(new TypeFilter<>(REnvironment.class), null, false).setNext(
-                        new CoercionStep<>(RType.Integer, false).setNext(new FindFirstStep<>("hello", String.class, null))))).getFirstCast();
+        PipelineStep<?, ?> steps = new FilterStep<>(new TypeFilter<>(REnvironment.class), null, false).setNext(
+                        new CoercionStep<>(RType.Integer, false).setNext(new FindFirstStep<>("hello", String.class, null)));
+
+        // without first cast of foreign objects
+        CastNode pipeline = createPipeline(steps, false);
+
+        assertChainedCast(pipeline, ChainedCastNode.class, FindFirstNode.class);
+        CastNode next = ((ChainedCastNode) pipeline).getFirstCast();
         assertChainedCast(next, FilterNode.class, CastIntegerBaseNode.class);
-        FindFirstNode findFirst = (FindFirstNode) ((ChainedCastNode) createPipeline(new FilterStep<>(new TypeFilter<>(REnvironment.class), null, false).setNext(
-                        new CoercionStep<>(RType.Integer, false).setNext(new FindFirstStep<>("hello", String.class, null))))).getSecondCast();
+
+        FindFirstNode findFirst = (FindFirstNode) ((ChainedCastNode) pipeline).getSecondCast();
         assertEquals("hello", findFirst.getDefaultValue());
+
+        // with first cast of foreign objects
+        pipeline = createPipeline(steps, true);
+        assertChainedCast(pipeline, ChainedCastNode.class, FindFirstNode.class);
+
+        next = ((ChainedCastNode) pipeline).getFirstCast();
+        assertChainedCast(next, ChainedCastNode.class, CastIntegerBaseNode.class);
+
+        next = ((ChainedCastNode) next).getFirstCast();
+        assertChainedCast(next, CastForeignNode.class, FilterNode.class);
+
     }
 
     private static void assertChainedCast(CastNode node, Class<?> expectedFirst, Class<?> expectedSecond) {
@@ -81,9 +114,10 @@ public class PipelineToCastNodeTests {
         assertTrue(expectedSecond.isInstance(((ChainedCastNode) node).getSecondCast()));
     }
 
-    private static CastNode createPipeline(PipelineStep<?, ?> lastStep) {
+    private static CastNode createPipeline(PipelineStep<?, ?> lastStep, boolean castForeign) {
         PipelineConfigBuilder configBuilder = new PipelineConfigBuilder("x");
         configBuilder.setValueForwarding(false);
+        configBuilder.setCastForeignObjects(castForeign);
         return PipelineToCastNode.convert(configBuilder.build(), lastStep, ForwardingAnalysisResult.INVALID);
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
index 6896d4cf0c35ad53ab21aa12a96d85cc0b02ebce..3ca986a2bb6fa5c664383b5bf2e67831fe6bd189 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
@@ -29,10 +29,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.interop.ForeignAccess;
-import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.interop.java.JavaInterop;
-import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.primitive.BinaryMapNode;
@@ -51,8 +47,6 @@ 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.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
-import com.oracle.truffle.r.runtime.interop.ForeignArray2RNodeGen;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmeticFactory;
@@ -63,7 +57,6 @@ import com.oracle.truffle.r.runtime.ops.UnaryArithmeticFactory;
  * operation is implemented by factory object given as a constructor parameter, e.g.
  * {@link com.oracle.truffle.r.runtime.ops.BinaryArithmetic.Add}
  */
-@ImportStatic({RRuntime.class, com.oracle.truffle.api.interop.Message.class})
 public abstract class BinaryArithmeticNode extends RBuiltinNode.Arg2 {
 
     protected static final int CACHE_LIMIT = 5;
@@ -156,68 +149,6 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode.Arg2 {
         return doLeftNull(right, left, classProfile);
     }
 
-    @Specialization(replaces = "doNumericVectorCached", guards = {"isForeignVector(left, hasSize)", "isNumericVector(right)"})
-    @TruffleBoundary
-    protected Object doForeignLeft(TruffleObject left, Object right,
-                    @SuppressWarnings("unused") @Cached("HAS_SIZE.createNode()") Node hasSize,
-                    @Cached("createForeignArray2R()") ForeignArray2R foreignArray2R,
-                    @Cached("createRecursive()") BinaryArithmeticNode recursive) {
-        Object o = foreignArray2R.execute(left, true);
-        return recursive.execute(o, right);
-    }
-
-    @Specialization(replaces = "doNumericVectorCached", guards = {"isNumericVector(left)", "isForeignVector(right, hasSize)"})
-    @TruffleBoundary
-    protected Object doForeignRight(Object left, TruffleObject right,
-                    @SuppressWarnings("unused") @Cached("HAS_SIZE.createNode()") Node hasSize,
-                    @Cached("createForeignArray2R()") ForeignArray2R foreignArray2R,
-                    @Cached("createRecursive()") BinaryArithmeticNode recursive) {
-        Object o = foreignArray2R.execute(right, true);
-        return recursive.execute(left, o);
-    }
-
-    @Specialization(replaces = "doNumericVectorCached", guards = {"isForeignVector(left, hasSize)", "isForeignVector(right, hasSize)"})
-    @TruffleBoundary
-    protected Object doForeignVector(TruffleObject left, TruffleObject right,
-                    @SuppressWarnings("unused") @Cached("HAS_SIZE.createNode()") Node hasSize,
-                    @Cached("createForeignArray2R()") ForeignArray2R leftForeignArray2R,
-                    @Cached("createForeignArray2R()") ForeignArray2R rightForeignArray2R,
-                    @Cached("createRecursive()") BinaryArithmeticNode recursive) {
-        Object oLeft = leftForeignArray2R.execute(left, true);
-        Object oRight = rightForeignArray2R.execute(right, true);
-        return recursive.execute(oLeft, oRight);
-    }
-
-    protected ForeignArray2R createForeignArray2R() {
-        return ForeignArray2RNodeGen.create();
-    }
-
-    protected boolean isForeignVector(Object obj, Node hasSize) {
-        return RRuntime.isForeignObject(obj) && (ForeignAccess.sendHasSize(hasSize, (TruffleObject) obj) || JavaInterop.isJavaObject(Iterable.class, (TruffleObject) obj));
-    }
-
-    protected BinaryArithmeticNode createRecursive() {
-        return BinaryArithmeticNodeGen.create(binary, unary);
-    }
-
-    @Specialization(guards = {"isForeignVector(right, hasSize)"})
-    protected Object doForeignLeftNull(RNull left, TruffleObject right,
-                    @SuppressWarnings("unused") @Cached("HAS_SIZE.createNode()") Node hasSize,
-                    @Cached("createForeignArray2R()") ForeignArray2R foreignArray2R,
-                    @Cached("createRecursive()") BinaryArithmeticNode recursive) {
-        Object oRight = foreignArray2R.execute(right, true);
-        return recursive.execute(left, oRight);
-    }
-
-    @Specialization(guards = {"isForeignVector(left, hasSize)"})
-    protected Object doForeignRightNull(TruffleObject left, RNull right,
-                    @SuppressWarnings("unused") @Cached("HAS_SIZE.createNode()") Node hasSize,
-                    @Cached("createForeignArray2R()") ForeignArray2R foreignArray2R,
-                    @Cached("createRecursive()") BinaryArithmeticNode recursive) {
-        Object oLeft = foreignArray2R.execute(left, true);
-        return recursive.execute(oLeft, right);
-    }
-
     @Fallback
     protected Object doInvalidType(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") Object right) {
         throw error(Message.NON_NUMERIC_BINARY);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
index ae3cdfeff6afb55e27e55aefa564646cbad8e700..4aac9d4b03aa25c3b7117f06684dac68da56df95 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
@@ -26,11 +26,8 @@ import com.oracle.truffle.api.CompilerAsserts;
 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.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.primitive.BinaryMapNode;
 import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode;
@@ -57,7 +54,6 @@ 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;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.BinaryLogic;
 import com.oracle.truffle.r.runtime.ops.BinaryLogic.And;
@@ -70,7 +66,6 @@ import com.oracle.truffle.r.runtime.ops.BooleanOperationFactory;
  * operation is implemented by factory object given as a constructor parameter, e.g.
  * {@link com.oracle.truffle.r.runtime.ops.BinaryLogic.And}.
  */
-@ImportStatic({ForeignArray2R.class, com.oracle.truffle.api.interop.Message.class})
 public abstract class BinaryBooleanNode extends RBuiltinNode.Arg2 {
 
     protected static final int CACHE_LIMIT = 5;
@@ -242,17 +237,6 @@ public abstract class BinaryBooleanNode extends RBuiltinNode.Arg2 {
         return (isRAbstractVector(value) && ((RAbstractVector) value).getLength() == 0);
     }
 
-    @Specialization(guards = {"isForeignVector(left, hasSize) || isForeignVector(right, hasSize)"})
-    protected Object doForeignVector(VirtualFrame frame, TruffleObject left, TruffleObject right,
-                    @SuppressWarnings("unused") @Cached("HAS_SIZE.createNode()") Node hasSize,
-                    @Cached("createForeignArray2R()") ForeignArray2R leftForeignArray2R,
-                    @Cached("createForeignArray2R()") ForeignArray2R rightForeignArray2R,
-                    @Cached("createRecursive()") BinaryBooleanNode recursive) {
-        Object oLeft = leftForeignArray2R.execute(left, true);
-        Object oRight = rightForeignArray2R.execute(right, true);
-        return recursive.execute(frame, oLeft, oRight);
-    }
-
     @Fallback
     protected Object doInvalidType(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") Object right) {
         throw error(Message.OPERATIONS_NUMERIC_LOGICAL_COMPLEX);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/CastForeignNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/CastForeignNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..450f30bb90ad4b7d6600b949ccf308d7a3e47e61
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/CastForeignNode.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017, 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 2 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 2 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
+ * 2 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.builtin.casts;
+
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.dsl.ImportStatic;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.nodes.unary.CastNode;
+import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
+
+@ImportStatic({ForeignArray2R.class, Message.class})
+public abstract class CastForeignNode extends CastNode {
+
+    protected CastForeignNode() {
+    }
+
+    @Specialization(guards = {"isForeignVector(obj, hasSize)"})
+    protected Object castForeign(TruffleObject obj,
+                    @Cached("HAS_SIZE.createNode()") Node hasSize,
+                    @Cached("createForeignArray2R()") ForeignArray2R foreignArray2R) {
+        return foreignArray2R.execute(obj, true);
+    }
+
+    @Fallback
+    protected Object passThrough(Object x) {
+        return x;
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineConfig.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineConfig.java
index 607f55a25861a11743c224f8c488bb4f2dc0e505..0e487adfd247a494ecf1bfeac924c0813216b5c0 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineConfig.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineConfig.java
@@ -35,12 +35,14 @@ public class PipelineConfig {
     private final String argumentName;
     private final MessageData defaultError;
     private final MessageData defaultWarning;
-    private boolean valueForwarding;
+    private final boolean valueForwarding;
+    private final boolean castForeign;
 
-    public PipelineConfig(String argumentName, MessageData defaultError, MessageData defaultWarning, boolean valueForwarding) {
+    public PipelineConfig(String argumentName, MessageData defaultError, MessageData defaultWarning, boolean valueForwarding, boolean castForeign) {
         this.defaultError = defaultError;
         this.defaultWarning = defaultWarning;
         this.valueForwarding = valueForwarding;
+        this.castForeign = castForeign;
         this.argumentName = argumentName;
     }
 
@@ -63,4 +65,8 @@ public class PipelineConfig {
     public boolean getValueForwarding() {
         return valueForwarding;
     }
+
+    public boolean getCastForeign() {
+        return castForeign;
+    }
 }
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 79aa7369fffad8721bea07bc47382e7d6ceeecda..12aaa0ec1f3df2f353fbc0bc633110f87b42698f 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
@@ -116,7 +116,9 @@ public final class PipelineToCastNode {
         boolean singleMapStep = firstStepIn.getNext() == null && firstStepIn instanceof MapIfStep;
         PipelineStep<?, ?> firstStep = singleMapStep ? ((MapIfStep<?, ?>) firstStepIn).withoutReturns() : firstStepIn;
 
-        Supplier<CastNode> originalPipelineFactory = () -> convert(firstStep, new CastNodeFactory(config.getDefaultError(), config.getDefaultWarning(), config.getDefaultDefaultMessage()));
+        CastNode firstCastNode = config.getCastForeign() ? CastForeignNodeGen.create() : null;
+        Supplier<CastNode> originalPipelineFactory = () -> convert(firstCastNode, firstStep,
+                        new CastNodeFactory(config.getDefaultError(), config.getDefaultWarning(), config.getDefaultDefaultMessage()));
 
         if (!config.getValueForwarding()) {
             return originalPipelineFactory.get();
@@ -132,12 +134,12 @@ public final class PipelineToCastNode {
     /**
      * Converts chain of pipeline steps to cast nodes.
      */
-    private static CastNode convert(PipelineStep<?, ?> firstStep, PipelineStepVisitor<CastNode> nodeFactory) {
+    private static CastNode convert(CastNode firstCastNode, PipelineStep<?, ?> firstStep, PipelineStepVisitor<CastNode> nodeFactory) {
         if (firstStep == null) {
             return null;
         }
 
-        CastNode prevCastNode = null;
+        CastNode prevCastNode = firstCastNode;
         PipelineStep<?, ?> currCastStep = firstStep;
         while (currCastStep != null) {
             CastNode node = currCastStep.accept(nodeFactory, prevCastNode);
@@ -145,8 +147,7 @@ public final class PipelineToCastNode {
                 if (prevCastNode == null) {
                     prevCastNode = node;
                 } else {
-                    CastNode finalPrevCastNode = prevCastNode;
-                    prevCastNode = new ChainedCastNode(finalPrevCastNode, node, currCastStep.getNext() == null);
+                    prevCastNode = new ChainedCastNode(prevCastNode, node, currCastStep.getNext() == null);
                 }
             }
 
@@ -261,8 +262,8 @@ public final class PipelineToCastNode {
         public CastNode visit(MapIfStep<?, ?> step, CastNode previous) {
             @SuppressWarnings("unchecked")
             ArgumentFilter<Object, Object> condition = (ArgumentFilter<Object, Object>) ArgumentFilterFactoryImpl.INSTANCE.createFilter(step.getFilter());
-            CastNode trueCastNode = PipelineToCastNode.convert(step.getTrueBranch(), this);
-            CastNode falseCastNode = PipelineToCastNode.convert(step.getFalseBranch(), this);
+            CastNode trueCastNode = PipelineToCastNode.convert(null, step.getTrueBranch(), this);
+            CastNode falseCastNode = PipelineToCastNode.convert(null, step.getFalseBranch(), this);
             return ConditionalMapNode.create(condition, trueCastNode, falseCastNode, ResultForArg.TRUE.equals(step.getFilter().resultForNull()),
                             ResultForArg.TRUE.equals(step.getFilter().resultForMissing()), step.isReturns());
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineConfigBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineConfigBuilder.java
index 9fa3ffa3109970c15cc104782385cd2fe69235d6..8d2e7119bc9a5a976ae6b160000aa00a8cd1035a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineConfigBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineConfigBuilder.java
@@ -39,6 +39,7 @@ public final class PipelineConfigBuilder {
     private MessageData defaultWarning;
 
     private boolean valueForwarding = true;
+    private boolean castForeign = true;
 
     public PipelineConfigBuilder(String argumentName) {
         this.argumentName = argumentName;
@@ -47,7 +48,7 @@ public final class PipelineConfigBuilder {
     }
 
     public PipelineConfig build() {
-        return new PipelineConfig(argumentName, defaultError, defaultWarning, valueForwarding);
+        return new PipelineConfig(argumentName, defaultError, defaultWarning, valueForwarding, castForeign);
     }
 
     void setDefaultError(MessageData defaultError) {
@@ -62,4 +63,9 @@ public final class PipelineConfigBuilder {
         this.valueForwarding = flag;
         return this;
     }
+
+    public PipelineConfigBuilder setCastForeignObjects(boolean flag) {
+        this.castForeign = flag;
+        return this;
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PreinitialPhaseBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PreinitialPhaseBuilder.java
index 3c959e0bb414bd8e34556e3c3ebfff77377daf82..b54e004571f27eb45d2fb3102d9ea09169466e58 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PreinitialPhaseBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PreinitialPhaseBuilder.java
@@ -96,6 +96,18 @@ public final class PreinitialPhaseBuilder extends InitialPhaseBuilder<Object> {
         return this;
     }
 
+    /**
+     * Determines whether foreign arrays are implicitly casted to a R vector/list or not. <br>
+     * The default setting is <code>true</code>.
+     * 
+     * @param flag
+     * @return
+     */
+    public PreinitialPhaseBuilder castForeignObjects(boolean flag) {
+        pipelineBuilder().getPipelineConfig().setCastForeignObjects(flag);
+        return this;
+    }
+
     public PreinitialPhaseBuilder defaultWarning(Message message, Object... args) {
         pipelineBuilder().getPipelineConfig().setDefaultWarning(new MessageData(message, args));
         return this;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java
index f90e615ee6ac2e7ea4b56b8ef5ff0c7f37804c84..88151421902d9518fbfeb23035b5ca4e27bcce3e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java
@@ -26,9 +26,7 @@ import java.util.function.IntFunction;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RError;
@@ -48,12 +46,9 @@ 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.RAbstractVector;
-import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
-import com.oracle.truffle.r.runtime.interop.ForeignArray2RNodeGen;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 import com.oracle.truffle.r.runtime.ops.na.NAProfile;
 
-@ImportStatic(RRuntime.class)
 public abstract class CastComplexNode extends CastBaseNode {
 
     private final NACheck naCheck = NACheck.create();
@@ -269,22 +264,6 @@ public abstract class CastComplexNode extends CastBaseNode {
         return ret;
     }
 
-    @Specialization(guards = "isForeignObject(obj)")
-    protected RComplexVector doForeignObject(TruffleObject obj,
-                    @Cached("createForeignArray2RNode()") ForeignArray2R foreignArray2R) {
-        Object o = foreignArray2R.execute(obj, true);
-        if (!RRuntime.isForeignObject(o)) {
-            if (o instanceof RComplexVector) {
-                return (RComplexVector) o;
-            }
-            o = castComplexRecursive(o);
-            if (o instanceof RComplexVector) {
-                return (RComplexVector) o;
-            }
-        }
-        throw error(RError.Message.CANNOT_COERCE_EXTERNAL_OBJECT_TO_VECTOR, "vector");
-    }
-
     public static CastComplexNode create() {
         return CastComplexNodeGen.create(true, true, true);
     }
@@ -296,8 +275,4 @@ public abstract class CastComplexNode extends CastBaseNode {
     public static CastComplexNode createNonPreserving() {
         return CastComplexNodeGen.create(false, false, false);
     }
-
-    protected ForeignArray2R createForeignArray2RNode() {
-        return ForeignArray2RNodeGen.create();
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java
index 1f4c55c3899a02c425977270b76ca47e747c0d20..c426860c0f999a558a6de930d99a750e1133cec7 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java
@@ -22,14 +22,10 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
-import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 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.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RExpression;
@@ -38,14 +34,9 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
-import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
-import com.oracle.truffle.r.runtime.interop.ForeignArray2RNodeGen;
 
-@ImportStatic(RRuntime.class)
 public abstract class CastExpressionNode extends CastBaseNode {
 
-    @Child private CastExpressionNode recursiveCastExpression;
-
     public abstract Object executeExpression(Object o);
 
     protected CastExpressionNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
@@ -113,16 +104,6 @@ public abstract class CastExpressionNode extends CastBaseNode {
         }
     }
 
-    @Specialization(guards = "isForeignObject(obj)")
-    protected RExpression doForeignObject(TruffleObject obj,
-                    @Cached("createForeignArray2RNode()") ForeignArray2R foreignArray2R) {
-        Object o = foreignArray2R.execute(obj, true);
-        if (!RRuntime.isForeignObject(o)) {
-            return (RExpression) castExpressionRecursive(o);
-        }
-        throw error(RError.Message.CANNOT_COERCE_EXTERNAL_OBJECT_TO_VECTOR, "vector");
-    }
-
     private static RExpression create(Object obj) {
         return RDataFactory.createExpression(new Object[]{obj});
     }
@@ -137,16 +118,4 @@ public abstract class CastExpressionNode extends CastBaseNode {
     public static CastExpressionNode createNonPreserving() {
         return CastExpressionNodeGen.create(false, false, false);
     }
-
-    protected ForeignArray2R createForeignArray2RNode() {
-        return ForeignArray2RNodeGen.create();
-    }
-
-    private Object castExpressionRecursive(Object o) {
-        if (recursiveCastExpression == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            recursiveCastExpression = insert(CastExpressionNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes()));
-        }
-        return recursiveCastExpression.executeExpression(o);
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java
index 181c0dc8e48ebbb798e4384366c9cd7cfdfc77b9..c66438279a68fe416dead3725adc170253c3d9ac 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java
@@ -24,9 +24,7 @@ package com.oracle.truffle.r.nodes.unary;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RError;
@@ -45,12 +43,9 @@ 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.RAbstractVector;
-import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
-import com.oracle.truffle.r.runtime.interop.ForeignArray2RNodeGen;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 import com.oracle.truffle.r.runtime.ops.na.NAProfile;
 
-@ImportStatic(RRuntime.class)
 public abstract class CastRawNode extends CastBaseNode {
 
     private final NACheck naCheck = NACheck.create();
@@ -317,22 +312,6 @@ public abstract class CastRawNode extends CastBaseNode {
         return result;
     }
 
-    @Specialization(guards = "isForeignObject(obj)")
-    protected RRawVector doForeignObject(TruffleObject obj,
-                    @Cached("createForeignArray2RNode()") ForeignArray2R foreignArray2R) {
-        Object o = foreignArray2R.execute(obj, true);
-        if (!RRuntime.isForeignObject(o)) {
-            if (o instanceof RRawVector) {
-                return (RRawVector) o;
-            }
-            o = castRawRecursive(o);
-            if (o instanceof RRawVector) {
-                return (RRawVector) o;
-            }
-        }
-        throw error(RError.Message.CANNOT_COERCE_EXTERNAL_OBJECT_TO_VECTOR, "vector");
-    }
-
     public static CastRawNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
         return CastRawNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
     }
@@ -340,8 +319,4 @@ public abstract class CastRawNode extends CastBaseNode {
     public static CastRawNode createNonPreserving() {
         return CastRawNodeGen.create(false, false, false);
     }
-
-    protected ForeignArray2R createForeignArray2RNode() {
-        return ForeignArray2RNodeGen.create();
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
index 047b9987bafdd659e8473a37c9af06d6b1cde0b0..2b45b6639ae5045f8d4941d354b0fc0bf958e45a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
@@ -24,13 +24,9 @@ package com.oracle.truffle.r.nodes.unary;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
@@ -41,14 +37,10 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
-import com.oracle.truffle.r.runtime.interop.ForeignArray2RNodeGen;
 
-@ImportStatic(RRuntime.class)
 public abstract class CastSymbolNode extends CastBaseNode {
 
     @Child private ToStringNode toString = ToStringNodeGen.create();
-    @Child private CastSymbolNode recursiveCastSymbol;
 
     protected CastSymbolNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
         this(preserveNames, preserveDimensions, preserveAttributes, false);
@@ -140,16 +132,6 @@ public abstract class CastSymbolNode extends CastBaseNode {
         return RDataFactory.createSymbolInterned(s);
     }
 
-    @Specialization(guards = "isForeignObject(obj)")
-    protected RSymbol doForeignObject(TruffleObject obj,
-                    @Cached("createForeignArray2RNode()") ForeignArray2R foreignArray2R) {
-        Object o = foreignArray2R.execute(obj, true);
-        if (!RRuntime.isForeignObject(o)) {
-            return (RSymbol) castSymbolRecursive(o);
-        }
-        throw error(RError.Message.CANNOT_COERCE_EXTERNAL_OBJECT_TO_VECTOR, "vector");
-    }
-
     @Override
     protected Object doOtherRFFI(Object mappedValue) {
         if (mappedValue instanceof RList) {
@@ -166,16 +148,4 @@ public abstract class CastSymbolNode extends CastBaseNode {
     public static CastSymbolNode createNonPreserving() {
         return CastSymbolNodeGen.create(false, false, false);
     }
-
-    protected ForeignArray2R createForeignArray2RNode() {
-        return ForeignArray2RNodeGen.create();
-    }
-
-    private Object castSymbolRecursive(Object o) {
-        if (recursiveCastSymbol == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            recursiveCastSymbol = insert(CastSymbolNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes()));
-        }
-        return recursiveCastSymbol.executeSymbol(o);
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java
index ce65ed44e29023665f06ee0f4e4741eba3c24e63..1f0892d7285603e2bf2950d8ba38a5b7df910ed3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java
@@ -26,11 +26,7 @@ import com.oracle.truffle.api.CompilerDirectives;
 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.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.interop.Message;
-import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.nodes.primitive.UnaryMapNode;
 import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -41,12 +37,10 @@ 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.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.UnaryArithmetic;
 import com.oracle.truffle.r.runtime.ops.UnaryArithmeticFactory;
 
-@ImportStatic({ForeignArray2R.class, Message.class})
 public abstract class UnaryArithmeticNode extends UnaryNode {
 
     protected final UnaryArithmeticFactory unary;
@@ -101,19 +95,6 @@ public abstract class UnaryArithmeticNode extends UnaryNode {
         return this;
     }
 
-    @Specialization(guards = {"isForeignVector(obj, hasSize)"})
-    protected Object doForeignVector(TruffleObject obj,
-                    @SuppressWarnings("unused") @Cached("HAS_SIZE.createNode()") Node hasSize,
-                    @Cached("createForeignArray2R()") ForeignArray2R foreignArray2R,
-                    @Cached("createRecursive()") UnaryArithmeticNode recursive) {
-        Object vec = foreignArray2R.execute(obj, true);
-        return recursive.execute(vec);
-    }
-
-    protected UnaryArithmeticNode createRecursive() {
-        return UnaryArithmeticNodeGen.create(unary);
-    }
-
     @Fallback
     protected Object invalidArgType(Object operand) {
         CompilerDirectives.transferToInterpreter();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/ForeignArray2R.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/ForeignArray2R.java
index 8d62b74ba44e9abf2dd02b38056682ab5978a462..9a75f0c138bc3483162f99115b8bca3264901fc6 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/ForeignArray2R.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/ForeignArray2R.java
@@ -191,7 +191,10 @@ public abstract class ForeignArray2R extends RBaseNode {
     }
 
     /**
-     * Coverts the elements collected from a foreign array or java iterable into a vector or list.
+     * Converts the elements collected from a foreign array or java iterable into a vector or list.
+     * 
+     * @param ce
+     * @return
      */
     public static RAbstractVector asAbstractVector(CollectedElements ce) {
         InteropTypeCheck.RType type = ce.typeCheck.getType();
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 9bf9e9368f2f318dbd3078f5b7d4591361adb640..e5c39e73442c2e5fb0170cdc5c7b44eb72731bc8 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
@@ -132996,9 +132996,9 @@ Error in as.character(to) :
   no method for coercing this external object to a vector
 
 ##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testAsXXX#
-#if (!any(R.version$engine == "FastR")) { cat('Error in as.complex(to) :', '<<<NEWLINE>>>', ' no method for coercing this external object to a vector', '<<<NEWLINE>>>') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));as.complex(to); }
+#if (!any(R.version$engine == "FastR")) { cat('Error in as.complex(to) :', '<<<NEWLINE>>>', ' cannot coerce type \'truffleobject\' to vector of type \'complex\'', '<<<NEWLINE>>>') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));as.complex(to); }
 Error in as.complex(to) :
-  no method for coercing this external object to a vector
+  cannot coerce type 'truffleobject' to vector of type 'complex'
 
 ##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testAsXXX#
 #if (!any(R.version$engine == "FastR")) { cat('Error in as.double(to) :', '<<<NEWLINE>>>', ' no method for coercing this external object to a vector', '<<<NEWLINE>>>') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));as.double(to); }
@@ -133021,9 +133021,9 @@ Error in as.logical(to) :
   no method for coercing this external object to a vector
 
 ##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testAsXXX#
-#if (!any(R.version$engine == "FastR")) { cat('Error in as.raw(to) :', '<<<NEWLINE>>>', ' no method for coercing this external object to a vector', '<<<NEWLINE>>>') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));as.raw(to); }
+#if (!any(R.version$engine == "FastR")) { cat('Error in as.raw(to) :', '<<<NEWLINE>>>', ' cannot coerce type \'truffleobject\' to vector of type \'raw\'', '<<<NEWLINE>>>') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));as.raw(to); }
 Error in as.raw(to) :
-  no method for coercing this external object to a vector
+  cannot coerce type 'truffleobject' to vector of type 'raw'
 
 ##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testAsXXX#
 #if (!any(R.version$engine == "FastR")) { cat('Error in as.symbol(to) :', '<<<NEWLINE>>>', ' no method for coercing this external object to a vector', '<<<NEWLINE>>>') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));as.symbol(to); }
@@ -133051,54 +133051,206 @@ Error in attr(to, which = "a") : external object cannot be attributed
 #if (!any(R.version$engine == "FastR")) { "com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); to$classAsArg(new.java.class(com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass)) }
 [1] "com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass"
 
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
-#if (!any(R.version$engine == "FastR")) { 'interopt.byte' } else { class(c(as.external.byte(123))) }
-[1] "interopt.byte"
-
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
-#if (!any(R.version$engine == "FastR")) { 'list' } else { class(c(1, as.external.byte(123))) }
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { 'list' } else { tc <- new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- new.external(tc); t1 <- new.external(tc); class(c(t, t1)) }
 [1] "list"
 
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
-#if (!any(R.version$engine == "FastR")) { 'list' } else { class(c(as.external.byte(123), 1)) }
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { 'list' } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); class(c(1, t)) }
 [1] "list"
 
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
-#if (!any(R.version$engine == "FastR")) { 'list' } else { class(c(as.external.byte(123), as.external.byte(234))) }
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { 'list' } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); class(c(t, 1)) }
 [1] "list"
 
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
-#if (!any(R.version$engine == "FastR")) { 'list' } else { tc <- new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- new.external(tc); t1 <- new.external(tc); class(c(t, t1)) }
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { 'list' } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); class(c(to)) }
 [1] "list"
 
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
-#if (!any(R.version$engine == "FastR")) { 'list' } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); class(c(1, t)) }
-[1] "list"
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c("1","2","3") } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listStringInt) }
+[1] "1" "2" "3"
 
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
-#if (!any(R.version$engine == "FastR")) { 'list' } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); class(c(t, 1)) }
-[1] "list"
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c("1","2","3","1","2","3") } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listStringInt, to$listStringInt) }
+[1] "1" "2" "3" "1" "2" "3"
 
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
-#if (!any(R.version$engine == "FastR")) { 'truffle.object' } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); class(c(to)) }
-[1] "truffle.object"
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c("TRUE","TRUE","FALSE") } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listStringBoolean) }
+[1] "TRUE"  "TRUE"  "FALSE"
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c("TRUE","TRUE","FALSE","TRUE","TRUE","FALSE") } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listStringBoolean, to$listStringBoolean) }
+[1] "TRUE"  "TRUE"  "FALSE" "TRUE"  "TRUE"  "FALSE"
 
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c("a","b","c") } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldCharArray) }
+[1] "a" "b" "c"
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
 #if (!any(R.version$engine == "FastR")) { c("a","b","c") } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldStringArray) }
 [1] "a" "b" "c"
 
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c("a","b","c") } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listChar) }
+[1] "a" "b" "c"
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
 #if (!any(R.version$engine == "FastR")) { c("a","b","c") } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listString) }
 [1] "a" "b" "c"
 
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
-#if (!any(R.version$engine == "FastR")) { c('a', 'b', 'c', 'a', 'b', 'c') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldStringArray, to$fieldStringArray) }
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c("a","b","c","a","b","c") } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldCharArray, to$fieldCharArray) }
 [1] "a" "b" "c" "a" "b" "c"
 
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
-#if (!any(R.version$engine == "FastR")) { c('a', 'b', 'c', 'a', 'b', 'c') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listString, to$listString) }
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c("a","b","c","a","b","c") } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldStringArray, to$fieldStringArray) }
+[1] "a" "b" "c" "a" "b" "c"
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c("a","b","c","a","b","c") } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listChar, to$listChar) }
+[1] "a" "b" "c" "a" "b" "c"
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c("a","b","c","a","b","c") } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listString, to$listString) }
 [1] "a" "b" "c" "a" "b" "c"
 
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c() } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listEmpty) }
+NULL
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c() } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listEmpty, to$listEmpty) }
+NULL
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldByteArray) }
+[1] 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldIntegerArray) }
+[1] 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldLongArray) }
+[1] 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldShortArray) }
+[1] 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listByte) }
+[1] 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listInteger) }
+[1] 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listLong) }
+[1] 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listShort) }
+[1] 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3,1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldByteArray, to$fieldByteArray) }
+[1] 1 2 3 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3,1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldIntegerArray, to$fieldIntegerArray) }
+[1] 1 2 3 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3,1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldLongArray, to$fieldLongArray) }
+[1] 1 2 3 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3,1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldShortArray, to$fieldShortArray) }
+[1] 1 2 3 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3,1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listByte, to$listByte) }
+[1] 1 2 3 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3,1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listInteger, to$listInteger) }
+[1] 1 2 3 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3,1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listLong, to$listLong) }
+[1] 1 2 3 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1,2,3,1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listShort, to$listShort) }
+[1] 1 2 3 1 2 3
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1.1,2.1,3.1) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldDoubleArray) }
+[1] 1.1 2.1 3.1
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1.1,2.1,3.1) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldFloatArray) }
+[1] 1.1 2.1 3.1
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1.1,2.1,3.1) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listDouble) }
+[1] 1.1 2.1 3.1
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1.1,2.1,3.1) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listFloat) }
+[1] 1.1 2.1 3.1
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1.1,2.1,3.1,1.1,2.1,3.1) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldDoubleArray, to$fieldDoubleArray) }
+[1] 1.1 2.1 3.1 1.1 2.1 3.1
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1.1,2.1,3.1,1.1,2.1,3.1) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldFloatArray, to$fieldFloatArray) }
+[1] 1.1 2.1 3.1 1.1 2.1 3.1
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1.1,2.1,3.1,1.1,2.1,3.1) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listDouble, to$listDouble) }
+[1] 1.1 2.1 3.1 1.1 2.1 3.1
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(1.1,2.1,3.1,1.1,2.1,3.1) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listFloat, to$listFloat) }
+[1] 1.1 2.1 3.1 1.1 2.1 3.1
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(TRUE,FALSE,TRUE) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldBooleanArray) }
+[1]  TRUE FALSE  TRUE
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(TRUE,FALSE,TRUE) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listBoolean) }
+[1]  TRUE FALSE  TRUE
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(TRUE,FALSE,TRUE,TRUE,FALSE,TRUE) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$fieldBooleanArray, to$fieldBooleanArray) }
+[1]  TRUE FALSE  TRUE  TRUE FALSE  TRUE
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineForeignObjects#
+#if (!any(R.version$engine == "FastR")) { c(TRUE,FALSE,TRUE,TRUE,FALSE,TRUE) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listBoolean, to$listBoolean) }
+[1]  TRUE FALSE  TRUE  TRUE FALSE  TRUE
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
+#if (!any(R.version$engine == "FastR")) { 'interopt.byte' } else { class(c(as.external.byte(123))) }
+[1] "interopt.byte"
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
+#if (!any(R.version$engine == "FastR")) { 'list' } else { class(c(1, as.external.byte(123))) }
+[1] "list"
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
+#if (!any(R.version$engine == "FastR")) { 'list' } else { class(c(as.external.byte(123), 1)) }
+[1] "list"
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testCombineInteropTypes#
+#if (!any(R.version$engine == "FastR")) { 'list' } else { class(c(as.external.byte(123), as.external.byte(234))) }
+[1] "list"
+
 ##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testConvertEmptyList#
 #if (!any(R.version$engine == "FastR")) { as.character(list()) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));as.character(to$listEmpty); }
 character(0)
@@ -133516,9 +133668,8 @@ Error in abs(to) : non-numeric argument to mathematical function
 [1] 1.1 3.1
 
 ##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testForeignUnaryArithmeticReduceOp#
-#if (!any(R.version$engine == "FastR")) { cat('Error in min(x, na.rm = na.rm) :', '<<<NEWLINE>>>', ' invalid \'type\' (external object) of argument', '<<<NEWLINE>>>') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));range(to) }
-Error in min(x, na.rm = na.rm) :
-  invalid 'type' (external object) of argument
+#if (!any(R.version$engine == "FastR")) { cat('Error in min(x, na.rm = na.rm) : invalid \'type\' (list) of argument', '<<<NEWLINE>>>') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));range(to) }
+Error in min(x, na.rm = na.rm) : invalid 'type' (list) of argument
 
 ##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testForeignVectorArithmeticOp#
 #if (!any(R.version$engine == "FastR")) { -c(1,2,3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));-(to$fieldByteArray) }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java
index d1c186b4355b8a5f17aa7f23969538dac3a7dbcd..6c62351cee58b76edf2d5d784269bc68e1e485e7 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java
@@ -339,17 +339,45 @@ public class TestJavaInterop extends TestBase {
         assertEvalFastR("class(c(as.external.byte(123), as.external.byte(234)))", "'list'");
         assertEvalFastR("class(c(as.external.byte(123), 1))", "'list'");
         assertEvalFastR("class(c(1, as.external.byte(123)))", "'list'");
+    }
+
+    @Test
+    public void testCombineForeignObjects() throws IllegalAccessException, IllegalArgumentException {
 
-        assertEvalFastR(CREATE_TRUFFLE_OBJECT + " class(c(to))", "'truffle.object'");
+        assertEvalFastR(CREATE_TRUFFLE_OBJECT + " class(c(to))", "'list'");
         assertEvalFastR("tc <- new.java.class('" + TEST_CLASS + "'); t <- new.external(tc); t1 <- new.external(tc); class(c(t, t1))", "'list'");
         assertEvalFastR(CREATE_TRUFFLE_OBJECT + " class(c(1, t))", "'list'");
         assertEvalFastR(CREATE_TRUFFLE_OBJECT + " class(c(t, 1))", "'list'");
 
         TestClass t = new TestClass();
-        assertEvalFastR(Ignored.Unimplemented, CREATE_TRUFFLE_OBJECT + " c(to$fieldStringArray)", toRVector(t.fieldStringArray, null));
-        assertEvalFastR(Ignored.Unimplemented, CREATE_TRUFFLE_OBJECT + " c(to$listString)", toRVector(t.listString, null));
-        assertEvalFastR(CREATE_TRUFFLE_OBJECT + " c(to$fieldStringArray, to$fieldStringArray)", "c('a', 'b', 'c', 'a', 'b', 'c')");
-        assertEvalFastR(CREATE_TRUFFLE_OBJECT + " c(to$listString, to$listString)", "c('a', 'b', 'c', 'a', 'b', 'c')");
+
+        testCombineForeignObjects("fieldBooleanArray", t.fieldBooleanArray);
+        testCombineForeignObjects("fieldByteArray", t.fieldByteArray);
+        testCombineForeignObjects("fieldCharArray", t.fieldCharArray);
+        testCombineForeignObjects("fieldDoubleArray", t.fieldDoubleArray);
+        testCombineForeignObjects("fieldFloatArray", t.fieldFloatArray);
+        testCombineForeignObjects("fieldIntegerArray", t.fieldIntegerArray);
+        testCombineForeignObjects("fieldLongArray", t.fieldLongArray);
+        testCombineForeignObjects("fieldShortArray", t.fieldShortArray);
+        testCombineForeignObjects("fieldStringArray", t.fieldStringArray);
+
+        testCombineForeignObjects("listBoolean", t.listBoolean);
+        testCombineForeignObjects("listByte", t.listByte);
+        testCombineForeignObjects("listChar", t.listChar);
+        testCombineForeignObjects("listDouble", t.listDouble);
+        testCombineForeignObjects("listFloat", t.listFloat);
+        testCombineForeignObjects("listInteger", t.listInteger);
+        testCombineForeignObjects("listLong", t.listLong);
+        testCombineForeignObjects("listShort", t.listShort);
+        testCombineForeignObjects("listString", t.listString);
+        testCombineForeignObjects("listStringInt", t.listStringInt);
+        testCombineForeignObjects("listStringBoolean", t.listStringBoolean);
+        testCombineForeignObjects("listEmpty", t.listEmpty);
+    }
+
+    private void testCombineForeignObjects(String field, Object fieldObject) {
+        assertEvalFastR(CREATE_TRUFFLE_OBJECT + " c(to$" + field + ")", toRVector(fieldObject, null));
+        assertEvalFastR(CREATE_TRUFFLE_OBJECT + " c(to$" + field + ", to$" + field + ")", c(fieldObject, fieldObject));
     }
 
     @Test
@@ -837,19 +865,19 @@ public class TestJavaInterop extends TestBase {
 
     @Test
     public void testAsXXX() throws IllegalArgumentException, IllegalAccessException {
-        testAsXXX("as.character");
-        testAsXXX("as.complex");
-        testAsXXX("as.double");
-        testAsXXX("as.expression");
-        testAsXXX("as.integer");
-        testAsXXX("as.logical");
-        testAsXXX("as.raw");
-        testAsXXX("as.symbol");
-        testAsXXX("as.vector");
+        testAsXXX("as.character", "character");
+        testAsXXX("as.complex", "complex");
+        testAsXXX("as.double", "double");
+        testAsXXX("as.expression", "expression");
+        testAsXXX("as.integer", "integer");
+        testAsXXX("as.logical", "logical");
+        testAsXXX("as.raw", "raw");
+        testAsXXX("as.symbol", "symbol");
+        testAsXXX("as.vector", null);
         // TODO more tests
     }
 
-    public void testAsXXX(String asXXX) throws IllegalArgumentException, IllegalAccessException {
+    public void testAsXXX(String asXXX, String type) throws IllegalArgumentException, IllegalAccessException {
         TestClass t = new TestClass();
 
         Field[] fields = t.getClass().getDeclaredFields();
@@ -938,9 +966,11 @@ public class TestJavaInterop extends TestBase {
         }
 
         if (asXXX.equals("as.expression")) {
-            assertEvalFastR(Output.IgnoreErrorContext, CREATE_TRUFFLE_OBJECT + asXXX + "(to);", errorIn("" + asXXX + "(to)", "no method for coercing this external object to a vector"));
+            assertEvalFastR(Output.IgnoreErrorContext, CREATE_TRUFFLE_OBJECT + asXXX + "(to);", errorIn(asXXX + "(to)", "no method for coercing this external object to a vector"));
+        } else if (asXXX.equals("as.raw") || asXXX.equals("as.complex")) {
+            assertEvalFastR(CREATE_TRUFFLE_OBJECT + asXXX + "(to);", errorIn(asXXX + "(to)", "cannot coerce type 'truffleobject' to vector of type '" + type + "'"));
         } else {
-            assertEvalFastR(CREATE_TRUFFLE_OBJECT + asXXX + "(to);", errorIn("" + asXXX + "(to)", "no method for coercing this external object to a vector"));
+            assertEvalFastR(CREATE_TRUFFLE_OBJECT + asXXX + "(to);", errorIn(asXXX + "(to)", "no method for coercing this external object to a vector"));
         }
     }
 
@@ -1251,7 +1281,7 @@ public class TestJavaInterop extends TestBase {
         assertEvalFastR(CREATE_TRUFFLE_OBJECT + "range(to$listStringInt)", "c('1', '3')");
         assertEvalFastR(CREATE_TRUFFLE_OBJECT + "range(to$listChar)", "c('a', 'c')");
 
-        assertEvalFastR(CREATE_TRUFFLE_OBJECT + "range(to)", errorIn("min(x, na.rm = na.rm)", "invalid 'type' (external object) of argument"));
+        assertEvalFastR(CREATE_TRUFFLE_OBJECT + "range(to)", errorIn("min(x, na.rm = na.rm)", "invalid 'type' (list) of argument"));
     }
 
     private String getRValue(Object value) {
@@ -1301,23 +1331,36 @@ public class TestJavaInterop extends TestBase {
     }
 
     private String toRVector(Object o, String asXXX) {
+        return toRVector(list(o), asXXX);
+    }
+
+    private String toRVector(Object[] l, String asXXX) {
+        return toRVector(Arrays.asList(l), asXXX);
+    }
+
+    private String c(Object a1, Object a2) {
+        List<Object> l = new ArrayList<>();
+        List<?> l1 = list(a1);
+        List<?> l2 = list(a2);
+        l.addAll(l1);
+        l.addAll(l2);
+        return toRVector(l, null);
+    }
+
+    private List<?> list(Object o) {
         if (o.getClass().isArray()) {
             List<Object> l = new ArrayList<>();
             for (int i = 0; i < Array.getLength(o); i++) {
                 l.add(Array.get(o, i));
             }
-            return toRVector(l, asXXX);
+            return l;
         } else if (o instanceof List) {
-            return toRVector((List<?>) o, asXXX);
+            return (List<?>) o;
         }
         Assert.fail(o + " should have been an array or list");
         return null;
     }
 
-    private String toRVector(Object[] l, String asXXX) {
-        return toRVector(Arrays.asList(l), asXXX);
-    }
-
     private String toRVector(List<?> l, String asXXX) {
         StringBuilder sb = new StringBuilder();
         if (asXXX != null) {