diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java
index a5d4ef1cf9be2b54b94d33b42e619386e88ca2e6..e51cdfd37d33c8d9a2c99961c349351b3f06ed0d 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java
@@ -165,8 +165,8 @@ public final class TruffleRLanguageImpl extends TruffleRLanguage implements Scop
                 unwrappedValue = promise.getValue();
             }
         }
-        unwrappedValue = RRuntime.asAbstractVector(unwrappedValue); // Wrap scalars "Integer",
-                                                                    // "Double" etc.
+        // Wrap scalars Integer, Double, etc.
+        unwrappedValue = RRuntime.convertScalarVectors(unwrappedValue);
         if (unwrappedValue instanceof RTypedValue) {
             return ((RTypedValue) unwrappedValue).getRType().getName();
         } else {
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceVectorNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceVectorNode.java
index 57616c037f499b4a5026fff990ed1da54cf5f924..32da1b5c50147f250972a2dba8c2d3efa6f85a81 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceVectorNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceVectorNode.java
@@ -149,7 +149,7 @@ public abstract class CoerceVectorNode extends FFIUpCallNode.Arg2 {
         }
 
         private static String getTypeName(Object val) {
-            Object value = RRuntime.asAbstractVector(val);
+            Object value = RRuntime.convertScalarVectors(val);
             if (value == null) {
                 return "null";
             }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java
index a906872082f8fb367e53f90a70af7c65a0b824ae..c0183e5841ef8b80453f77a7ce2e3332e32d2d49 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java
@@ -47,7 +47,7 @@ public final class CompleteCases extends RExternalBuiltinNode {
     }
 
     private int checkAbstractVectorLength(int len, Object obj) {
-        Object entry = RRuntime.asAbstractVector(obj);
+        Object entry = RRuntime.convertScalarVectors(obj);
         if (entry instanceof RAbstractVector) {
             RAbstractVector vector = (RAbstractVector) entry;
             int entryLength = vector.isMatrix() ? vector.getDimensions()[0] : vector.getLength();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java
index 8fc9cbac25e432750c93e586f60457fdddf72eff..98d1def9c8a29e78cdaf166ba10831f182b81e39 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java
@@ -106,7 +106,7 @@ public abstract class AsFunction extends RBuiltinNode.Arg2 {
                     } else {
                         defaultValue = ReadVariableNode.create(symbol.getName());
                     }
-                } else if (RRuntime.asAbstractVector(arg) instanceof RAttributable) {
+                } else if (RRuntime.convertScalarVectors(arg) instanceof RAttributable) {
                     defaultValue = ConstantNode.create(arg);
                 } else {
                     throw RInternalError.unimplemented();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DatePOSIXFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DatePOSIXFunctions.java
index 963a91850bce768380aa729a5abe1be9d79a090d..49f536b7eeefd197ee064f91445ece6f6ad4345d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DatePOSIXFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DatePOSIXFunctions.java
@@ -226,12 +226,12 @@ public class DatePOSIXFunctions {
         @Specialization
         @TruffleBoundary
         protected RDoubleVector asPOSIXct(RAbstractListVector x, String tz) {
-            RAbstractVector secVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(0));
-            RAbstractVector minVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(1));
-            RAbstractVector hourVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(2));
-            RAbstractVector mdayVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(3));
-            RAbstractVector monVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(4));
-            RAbstractVector yearVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(5));
+            RAbstractVector secVector = (RAbstractVector) RRuntime.convertScalarVectors(x.getDataAt(0));
+            RAbstractVector minVector = (RAbstractVector) RRuntime.convertScalarVectors(x.getDataAt(1));
+            RAbstractVector hourVector = (RAbstractVector) RRuntime.convertScalarVectors(x.getDataAt(2));
+            RAbstractVector mdayVector = (RAbstractVector) RRuntime.convertScalarVectors(x.getDataAt(3));
+            RAbstractVector monVector = (RAbstractVector) RRuntime.convertScalarVectors(x.getDataAt(4));
+            RAbstractVector yearVector = (RAbstractVector) RRuntime.convertScalarVectors(x.getDataAt(5));
             TimeZone zone;
             if (tz.isEmpty()) {
                 zone = RContext.getInstance().getSystemTimeZone();
@@ -285,12 +285,12 @@ public class DatePOSIXFunctions {
         @TruffleBoundary
         protected RDoubleVector posix2date(RAbstractListVector x,
                         @Cached("create()") SetClassAttributeNode setClassAttrNode) {
-            RAbstractVector secVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(0));
-            RAbstractVector minVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(1));
-            RAbstractVector hourVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(2));
-            RAbstractVector mdayVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(3));
-            RAbstractVector monVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(4));
-            RAbstractVector yearVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(5));
+            RAbstractVector secVector = (RAbstractVector) RRuntime.convertScalarVectors(x.getDataAt(0));
+            RAbstractVector minVector = (RAbstractVector) RRuntime.convertScalarVectors(x.getDataAt(1));
+            RAbstractVector hourVector = (RAbstractVector) RRuntime.convertScalarVectors(x.getDataAt(2));
+            RAbstractVector mdayVector = (RAbstractVector) RRuntime.convertScalarVectors(x.getDataAt(3));
+            RAbstractVector monVector = (RAbstractVector) RRuntime.convertScalarVectors(x.getDataAt(4));
+            RAbstractVector yearVector = (RAbstractVector) RRuntime.convertScalarVectors(x.getDataAt(5));
 
             int length = max(secVector.getLength(), minVector.getLength(), hourVector.getLength(), mdayVector.getLength(), monVector.getLength(), yearVector.getLength());
             double[] data = new double[length];
@@ -344,12 +344,12 @@ public class DatePOSIXFunctions {
         @Specialization
         @TruffleBoundary
         protected RStringVector format(RAbstractListVector x, RAbstractStringVector format, boolean usetz) {
-            RAbstractDoubleVector secVector = (RAbstractDoubleVector) RRuntime.asAbstractVector(x.getDataAt(0));
-            RAbstractIntVector minVector = (RAbstractIntVector) RRuntime.asAbstractVector(x.getDataAt(1));
-            RAbstractIntVector hourVector = (RAbstractIntVector) RRuntime.asAbstractVector(x.getDataAt(2));
-            RAbstractIntVector mdayVector = (RAbstractIntVector) RRuntime.asAbstractVector(x.getDataAt(3));
-            RAbstractIntVector monVector = (RAbstractIntVector) RRuntime.asAbstractVector(x.getDataAt(4));
-            RAbstractIntVector yearVector = (RAbstractIntVector) RRuntime.asAbstractVector(x.getDataAt(5));
+            RAbstractDoubleVector secVector = (RAbstractDoubleVector) RRuntime.convertScalarVectors(x.getDataAt(0));
+            RAbstractIntVector minVector = (RAbstractIntVector) RRuntime.convertScalarVectors(x.getDataAt(1));
+            RAbstractIntVector hourVector = (RAbstractIntVector) RRuntime.convertScalarVectors(x.getDataAt(2));
+            RAbstractIntVector mdayVector = (RAbstractIntVector) RRuntime.convertScalarVectors(x.getDataAt(3));
+            RAbstractIntVector monVector = (RAbstractIntVector) RRuntime.convertScalarVectors(x.getDataAt(4));
+            RAbstractIntVector yearVector = (RAbstractIntVector) RRuntime.convertScalarVectors(x.getDataAt(5));
             ZoneId zone;
             DateTimeFormatterBuilder[] builders = createFormatters(format, false);
             String tzone = getTimeZomeFromAttribute(x);
@@ -733,7 +733,7 @@ public class DatePOSIXFunctions {
 
     private static String getTimeZomeFromAttribute(RAbstractListVector x) {
         Object attr = x.getAttributes().get("tzone");
-        RAbstractVector vector = (RAbstractVector) RRuntime.asAbstractVector(attr);
+        RAbstractVector vector = (RAbstractVector) RRuntime.convertScalarVectors(attr);
         if (vector.getLength() == 0) {
             return "";
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
index c96c928113e469a5501ce6b7ead8667af62babcc..c1b7c425c19e25c9a26bcfac386c3e2d3625aa36 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
@@ -18,6 +18,7 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -154,6 +155,6 @@ public abstract class Prod extends RBuiltinNode.Arg2 {
 
     @Fallback
     protected Object prod(Object o) {
-        throw RError.error(this, RError.Message.INVALID_TYPE_ARGUMENT, ((RTypedValue) RRuntime.asAbstractVector(o)).getRType().getName());
+        throw error(RError.Message.INVALID_TYPE_ARGUMENT, Predef.typeName().apply(o));
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java
index 56d5d6be3ed430851ed4a990bbc6cab9c95fe72e..681396be29706924bf7f3d910b6a638a3f6e7ae8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java
@@ -50,9 +50,9 @@ import com.oracle.truffle.r.nodes.unary.CastLogicalNode;
 import com.oracle.truffle.r.nodes.unary.CastLogicalNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
+import com.oracle.truffle.r.nodes.unary.CastToVectorNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -83,6 +83,7 @@ public abstract class VApply extends RBuiltinNode.Arg4 {
 
     private final ConditionProfile useNamesProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile dimsProfile = ConditionProfile.createBinaryProfile();
+    private final ConditionProfile zeroLengthProfile = ConditionProfile.createBinaryProfile();
     private final NACheck naCheck = NACheck.create();
 
     @Child private LapplyInternalNode doApply = LapplyInternalNodeGen.create();
@@ -96,6 +97,8 @@ public abstract class VApply extends RBuiltinNode.Arg4 {
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
     @Child private SetNamesAttributeNode setNamesNode = SetNamesAttributeNode.create();
 
+    @Child private CastToVectorNode castToVector = CastToVectorNode.create();
+
     static {
         Casts casts = new Casts(VApply.class);
         casts.arg("X").mapNull(emptyList());
@@ -104,44 +107,44 @@ public abstract class VApply extends RBuiltinNode.Arg4 {
         casts.arg("USE.NAMES").defaultError(RError.Message.INVALID_VALUE, "USE.NAMES").mustBe(numericValue()).asLogicalVector().findFirst().mustNotBeNA().map(toBoolean());
     }
 
-    private Object castComplex(Object operand, boolean preserveAllAttr) {
+    private Object castComplex(Object operand) {
         if (castComplex == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            castComplex = insert(CastComplexNodeGen.create(true, preserveAllAttr, preserveAllAttr));
+            castComplex = insert(CastComplexNodeGen.create(true, false, false));
         }
-        return castComplex.doCast(operand);
+        return castToVector.doCast(castComplex.doCast(operand));
     }
 
-    private Object castDouble(Object operand, boolean preserveAllAttr) {
+    private Object castDouble(Object operand) {
         if (castDouble == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            castDouble = insert(CastDoubleNodeGen.create(true, preserveAllAttr, preserveAllAttr));
+            castDouble = insert(CastDoubleNodeGen.create(true, false, false));
         }
-        return castDouble.doCast(operand);
+        return castToVector.doCast(castDouble.doCast(operand));
     }
 
-    private Object castInteger(Object operand, boolean preserveAllAttr) {
+    private Object castInteger(Object operand) {
         if (castInteger == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            castInteger = insert(CastIntegerNodeGen.create(true, preserveAllAttr, preserveAllAttr));
+            castInteger = insert(CastIntegerNodeGen.create(true, false, false));
         }
-        return castInteger.doCast(operand);
+        return castToVector.doCast(castInteger.doCast(operand));
     }
 
-    private Object castLogical(Object operand, boolean preserveAllAttr) {
+    private Object castLogical(Object operand) {
         if (castLogical == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            castLogical = insert(CastLogicalNodeGen.create(true, preserveAllAttr, preserveAllAttr));
+            castLogical = insert(CastLogicalNodeGen.create(true, false, false));
         }
-        return castLogical.doCast(operand);
+        return castToVector.doCast(castLogical.doCast(operand));
     }
 
-    private Object castString(Object operand, boolean preserveAllAttr) {
+    private Object castString(Object operand) {
         if (castString == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            castString = insert(CastStringNodeGen.create(true, preserveAllAttr, preserveAllAttr));
+            castString = insert(CastStringNodeGen.create(true, false, false));
         }
-        return castString.doCast(operand);
+        return castToVector.doCast(castString.doCast(operand));
     }
 
     @Specialization
@@ -172,7 +175,7 @@ public abstract class VApply extends RBuiltinNode.Arg4 {
         Object[] applyResult = doApply.execute(frame, vecMat, fun);
 
         RVector<?> result;
-        boolean applyResultZeroLength = applyResult.length == 0;
+        boolean applyResultZeroLength = zeroLengthProfile.profile(applyResult.length == 0);
 
         naCheck.enable(true);
         // TODO check funValueLen against length of result
@@ -223,7 +226,7 @@ public abstract class VApply extends RBuiltinNode.Arg4 {
         double[] newArray = new double[values.length * len];
         int ind = 0;
         for (int i = 0; i < values.length; i++) {
-            RAbstractDoubleVector v = (RAbstractDoubleVector) RRuntime.asAbstractVector(castDouble(values[i], false));
+            RAbstractDoubleVector v = (RAbstractDoubleVector) castDouble(values[i]);
             for (int j = 0; j < v.getLength(); j++) {
                 double val = v.getDataAt(j);
                 naCheck.check(val);
@@ -237,7 +240,7 @@ public abstract class VApply extends RBuiltinNode.Arg4 {
         int[] newArray = new int[values.length * len];
         int ind = 0;
         for (int i = 0; i < values.length; i++) {
-            RAbstractIntVector v = (RAbstractIntVector) RRuntime.asAbstractVector(castInteger(values[i], false));
+            RAbstractIntVector v = (RAbstractIntVector) castInteger(values[i]);
             for (int j = 0; j < v.getLength(); j++) {
                 int val = v.getDataAt(j);
                 naCheck.check(val);
@@ -251,7 +254,7 @@ public abstract class VApply extends RBuiltinNode.Arg4 {
         byte[] newArray = new byte[values.length * len];
         int ind = 0;
         for (int i = 0; i < values.length; i++) {
-            RAbstractLogicalVector v = (RAbstractLogicalVector) RRuntime.asAbstractVector(castLogical(values[i], false));
+            RAbstractLogicalVector v = (RAbstractLogicalVector) castLogical(values[i]);
             for (int j = 0; j < v.getLength(); j++) {
                 byte val = v.getDataAt(j);
                 naCheck.check(val);
@@ -265,7 +268,7 @@ public abstract class VApply extends RBuiltinNode.Arg4 {
         String[] newArray = new String[values.length * len];
         int ind = 0;
         for (int i = 0; i < values.length; i++) {
-            RAbstractStringVector v = (RAbstractStringVector) RRuntime.asAbstractVector(castString(values[i], false));
+            RAbstractStringVector v = (RAbstractStringVector) castString(values[i]);
             for (int j = 0; j < v.getLength(); j++) {
                 String val = v.getDataAt(j);
                 naCheck.check(val);
@@ -279,7 +282,7 @@ public abstract class VApply extends RBuiltinNode.Arg4 {
         double[] newArray = new double[values.length * len * 2];
         int ind = 0;
         for (int i = 0; i < values.length; i++) {
-            RAbstractComplexVector v = (RAbstractComplexVector) RRuntime.asAbstractVector(castComplex(values[i], false));
+            RAbstractComplexVector v = (RAbstractComplexVector) castComplex(values[i]);
             for (int j = 0; j < v.getLength(); j++) {
                 RComplex val = v.getDataAt(j);
                 naCheck.check(val);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
index 143286861af82a99f79bd35bbf5d0f5d780dacc7..d1f913348016edbc453d52d9128a5c5d107670bd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
@@ -71,7 +71,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
         int ns = s.getLength();
         String[] t = new String[ns];
         for (int i = 0; i < ns; i++) {
-            Object tmp = RRuntime.asAbstractVector(s.getDataAtAsObject(i));
+            Object tmp = RRuntime.convertScalarVectors(s.getDataAtAsObject(i));
             final String pbuf;
             if (tmp == null || tmp == RNull.instance) {
                 pbuf = RRuntime.NULL;
@@ -165,7 +165,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
         int ns = s.getLength();
 
         RAbstractStringVector names;
-        names = Utils.castTo(RRuntime.asAbstractVector(s.getNames()));
+        names = Utils.castTo(RRuntime.convertScalarVectors(s.getNames()));
 
         if (ns > 0) {
             int npr = (ns <= pp.getMax() + 1) ? ns : pp.getMax();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PairListPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PairListPrinter.java
index 8d357469522dcb9584c6a379ea3c8517efa14423..c73fabdda712ae98656ae584182d7289738e7341 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PairListPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PairListPrinter.java
@@ -50,7 +50,7 @@ final class PairListPrinter extends AbstractValuePrinter<RPairList> {
         if (dims != null && dims.getLength() > 1) {
             String[] t = new String[ns];
             for (int i = 0; i < ns; i++) {
-                Object tmp = RRuntime.asAbstractVector(s.getDataAtAsObject(i));
+                Object tmp = RRuntime.convertScalarVectors(s.getDataAtAsObject(i));
                 final String pbuf;
                 if (tmp == null || tmp == RNull.instance) {
                     pbuf = RRuntime.NULL;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java
index 611ee0d6eae2e000a2f3ef45a855f3e740a1f942..e2a12e3ae18c0977f6db8c47300dac10950c6080 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java
@@ -81,7 +81,7 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
                 if (dims.getLength() == 1) {
                     RList t = Utils.<RList> castTo(getDimNames(vector));
                     if (t != null && t.getDataAt(0) != null) {
-                        RAbstractStringVector nn = Utils.castTo(RRuntime.asAbstractVector(t.getNames()));
+                        RAbstractStringVector nn = Utils.castTo(RRuntime.convertScalarVectors(t.getNames()));
 
                         if (nn != null) {
                             title = nn.getDataAt(0);
@@ -90,7 +90,7 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
                         }
 
                         jobMode = vector.getLength() == 0 ? JobMode.namedEmpty : JobMode.named;
-                        names = Utils.castTo(RRuntime.asAbstractVector(t.getDataAt(0)));
+                        names = Utils.castTo(RRuntime.convertScalarVectors(t.getDataAt(0)));
                     } else {
                         title = null;
                         names = null;
@@ -112,7 +112,7 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
                 Object namesAttr = Utils.castTo(getNames(vector));
                 if (namesAttr != null) {
                     if (vector.getLength() > 0) {
-                        names = Utils.castTo(RRuntime.asAbstractVector(namesAttr));
+                        names = Utils.castTo(RRuntime.convertScalarVectors(namesAttr));
                         jobMode = JobMode.named;
                     } else {
                         names = null;
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 965ea3aa0343b8228cbad4d89ebaf6c77639dad6..0db087a2824d21ad167cd17001cb1888360f0fd2 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
@@ -772,7 +772,7 @@ public final class CastBuilder {
         public static Function<Object, String> typeName() {
             return arg -> {
                 CompilerAsserts.neverPartOfCompilation();
-                return ((RTypedValue) RRuntime.asAbstractVector(arg)).getRType().getName();
+                return ((RTypedValue) RRuntime.convertScalarVectors(arg)).getRType().getName();
             };
         }
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyScalarNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyScalarNode.java
index 8c1938e5e35ebe51cbf7bed9555ba1a74755cc7e..91b95219b651e391900dd7ffbe8cc4d633cb6eeb 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyScalarNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyScalarNode.java
@@ -45,7 +45,7 @@ public abstract class ClassHierarchyScalarNode extends UnaryNode {
     public static String get(Object arg) {
         CompilerAsserts.neverPartOfCompilation();
 
-        Object v = RRuntime.asAbstractVector(arg);
+        Object v = RRuntime.convertScalarVectors(arg);
         if (v instanceof RAttributable) {
             RStringVector classHierarchy = ClassHierarchyNode.getClassHierarchy(v);
             return classHierarchy.getLength() == 0 ? "" : classHierarchy.getDataAt(0);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/TypeofNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/TypeofNode.java
index c2e606b1f73a542fce854d221e417ee5848b8d36..b41f76c5bbe2f89b07c633ee5caf81455e58faf5 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/TypeofNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/TypeofNode.java
@@ -93,7 +93,7 @@ public abstract class TypeofNode extends UnaryNode {
 
     public static RType getTypeof(Object operand) {
         CompilerAsserts.neverPartOfCompilation();
-        return ((RTypedValue) RRuntime.asAbstractVector(operand)).getRType();
+        return ((RTypedValue) RRuntime.convertScalarVectors(operand)).getRType();
     }
 
     public static TypeofNode create() {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
index 4ae8e1bc7916132740624742e253acf270df06fd..b9c6f7c7cc63342abfd2cec77495d9da3cb95749 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
@@ -53,13 +53,14 @@ import com.oracle.truffle.r.runtime.data.RS4Object;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
+import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 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.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
-import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxCall;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
@@ -717,7 +718,7 @@ public class RDeparse {
 
         @SuppressWarnings("try")
         private DeparseVisitor appendConstant(Object originalValue) {
-            Object value = RRuntime.asAbstractVector(originalValue);
+            Object value = RRuntime.convertScalarVectors(originalValue);
             if (value instanceof RExpression) {
                 append("expression(").appendListContents((RExpression) value).append(')');
             } else if (value instanceof RAbstractListVector) {
@@ -725,10 +726,10 @@ public class RDeparse {
                 try (C c = withAttributes(obj)) {
                     append("list(").appendListContents(obj).append(')');
                 }
-            } else if (value instanceof RAbstractVector) {
-                RAbstractVector obj = (RAbstractVector) value;
+            } else if (value instanceof RAbstractAtomicVector) {
+                RAbstractVector obj = (RAbstractAtomicVector) value;
                 try (C c = withAttributes(obj)) {
-                    appendVector((RAbstractVector) value);
+                    appendVector((RAbstractAtomicVector) value);
                 }
             } else if (value instanceof RNull) {
                 append("NULL");
@@ -745,7 +746,6 @@ public class RDeparse {
                 }
             } else if (value instanceof RPairList) {
                 RPairList arglist = (RPairList) value;
-                assert arglist.getType() == null || arglist.getType() == SEXPTYPE.LISTSXP : arglist.getType();
                 append("pairlist(");
                 int i = 0;
                 boolean lbreak = false;
@@ -761,7 +761,6 @@ public class RDeparse {
                         }
                     }
                     appendValue(arglist.car());
-
                     arglist = next(arglist);
                 }
                 append(')');
@@ -795,7 +794,7 @@ public class RDeparse {
             } else if (value instanceof TruffleObject) {
                 append("<truffle object>");
             } else {
-                throw RInternalError.shouldNotReachHere("unexpected: " + value);
+                throw RInternalError.shouldNotReachHere("unexpected type while deparsing constant: " + value == null ? "null" : value.getClass().getSimpleName());
             }
             return this;
         }
@@ -857,7 +856,7 @@ public class RDeparse {
             assert v != null;
             assert !(v instanceof RSyntaxElement) : v.getClass();
 
-            Object value = RRuntime.asAbstractVector(v);
+            Object value = RRuntime.convertScalarVectors(v);
             assert value instanceof RTypedValue : v.getClass();
 
             try {
@@ -893,13 +892,21 @@ public class RDeparse {
             }
         }
 
-        private void appendVector(RAbstractVector vec) {
-            SEXPTYPE type = SEXPTYPE.typeForClass(vec.getClass());
+        private void appendVector(RAbstractAtomicVector vec) {
             int len = vec.getLength();
             if (len == 0) {
                 append(vec.getRType().getClazz() + "(0)");
+            } else if (vec instanceof RAbstractRawVector) {
+                append("as.raw(c(");
+                for (int i = 0; i < len; i++) {
+                    if (i > 0) {
+                        append(", ");
+                    }
+                    vecElement2buff(vec.getDataAtAsObject(i), false);
+                }
+                append("))");
             } else if (len == 1) {
-                vecElement2buff(type, vec.getDataAtAsObject(0), true);
+                vecElement2buff(vec.getDataAtAsObject(0), true);
             } else {
                 RIntSequence sequence = asIntSequence(vec);
                 if (sequence != null) {
@@ -907,25 +914,14 @@ public class RDeparse {
                     return;
                 } else {
                     // TODO COMPAT?
-                    if (type == SEXPTYPE.RAWSXP) {
-                        append("as.raw(c(");
-                        for (int i = 0; i < len; i++) {
-                            if (i > 0) {
-                                append(", ");
-                            }
-                            vecElement2buff(type, vec.getDataAtAsObject(i), false);
-                        }
-                        append("))");
-                    } else {
-                        append("c(");
-                        for (int i = 0; i < len; i++) {
-                            if (i > 0) {
-                                append(", ");
-                            }
-                            vecElement2buff(type, vec.getDataAtAsObject(i), false);
+                    append("c(");
+                    for (int i = 0; i < len; i++) {
+                        if (i > 0) {
+                            append(", ");
                         }
-                        append(')');
+                        vecElement2buff(vec.getDataAtAsObject(i), false);
                     }
+                    append(')');
                 }
             }
         }
@@ -952,44 +948,37 @@ public class RDeparse {
             return RDataFactory.createIntSequence(start, 1, intVec.getLength());
         }
 
-        private DeparseVisitor vecElement2buff(SEXPTYPE type, Object element, boolean singleElement) {
-            switch (type) {
-                case STRSXP:
-                    String s = (String) element;
-                    append(RRuntime.isNA(s) ? (singleElement ? "NA_character_" : "NA") : RRuntime.escapeString(s, true, true));
-                    break;
-                case LGLSXP:
-                    append(RRuntime.logicalToString((byte) element));
-                    break;
-                case REALSXP:
-                    double d = (double) element;
-                    append(RRuntime.isNA(d) ? (singleElement ? "NA_real_" : "NA") : RContext.getRRuntimeASTAccess().encodeDouble(d));
-                    break;
-                case INTSXP:
-                    int i = (int) element;
-                    if (RRuntime.isNA(i)) {
-                        append((singleElement ? "NA_integer_" : "NA"));
-                    } else {
-                        append(RRuntime.intToStringNoCheck(i));
-                        if ((opts & KEEPINTEGER) != 0) {
-                            append('L');
-                        }
-                    }
-                    break;
-                case CPLXSXP:
-                    RComplex c = (RComplex) element;
-                    if (RRuntime.isNA(c)) {
-                        append((singleElement ? "NA_complex_" : "NA"));
-                    } else {
-                        append(RContext.getRRuntimeASTAccess().encodeComplex(c));
+        private DeparseVisitor vecElement2buff(Object element, boolean singleElement) {
+            if (element instanceof String) {
+                String s = (String) element;
+                append(RRuntime.isNA(s) ? (singleElement ? "NA_character_" : "NA") : RRuntime.escapeString(s, true, true));
+            } else if (element instanceof Byte) {
+                // simply "NA" is already the logical NA, so no special handling needed
+                append(RRuntime.logicalToString((byte) element));
+            } else if (element instanceof Double) {
+                double d = (double) element;
+                append(RRuntime.isNA(d) ? (singleElement ? "NA_real_" : "NA") : RContext.getRRuntimeASTAccess().encodeDouble(d));
+            } else if (element instanceof Integer) {
+                int i = (int) element;
+                if (RRuntime.isNA(i)) {
+                    append((singleElement ? "NA_integer_" : "NA"));
+                } else {
+                    append(RRuntime.intToStringNoCheck(i));
+                    if ((opts & KEEPINTEGER) != 0) {
+                        append('L');
                     }
-                    break;
-                case RAWSXP:
-                    RRaw r = (RRaw) element;
-                    append(Utils.stringFormat("0x%02x", r.getValue()));
-                    break;
-                default:
-                    throw RInternalError.shouldNotReachHere("unexpected SEXPTYPE: " + type);
+                }
+            } else if (element instanceof RComplex) {
+                RComplex c = (RComplex) element;
+                if (RRuntime.isNA(c)) {
+                    append((singleElement ? "NA_complex_" : "NA"));
+                } else {
+                    append(RContext.getRRuntimeASTAccess().encodeComplex(c));
+                }
+            } else if (element instanceof RRaw) {
+                append(Utils.stringFormat("0x%02x", ((RRaw) element).getValue()));
+            } else {
+                throw RInternalError.shouldNotReachHere("unexpected vector element type during deparsing: " + (element == null ? "null" : element.getClass().getSimpleName()));
             }
             return this;
         }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java
index 2cca8bd51cab6fa657fa75ae7a3df5db8d3a7c34..57860a82591b1eca7b7c0855efd1a209ce2400a1 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java
@@ -32,6 +32,7 @@ import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 /**
@@ -377,10 +378,10 @@ public class ROptions {
     }
 
     private static Object coerceStringVector(Object value, String name) throws OptionsException {
-        Object valueAbs = RRuntime.asAbstractVector(value);
+        Object valueAbs = RRuntime.convertScalarVectors(value);
         // TODO supposed to be coerced
-        if (valueAbs instanceof RStringVector) {
-            String p = ((RStringVector) valueAbs).getDataAt(0);
+        if (valueAbs instanceof RAbstractStringVector) {
+            String p = ((RAbstractStringVector) valueAbs).getDataAt(0);
             if (p.length() == 0 || RRuntime.isNA(p)) {
                 throw OptionsException.createInvalid(name);
             } else {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
index 27f169e4e932b40e4455e1d399d66bc35e891f40..144cb8f2ac25ace0926f56dce84638b94b966c50 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
@@ -29,6 +29,7 @@ import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RInteger;
 import com.oracle.truffle.r.runtime.data.RLogical;
 import com.oracle.truffle.r.runtime.data.RRaw;
+import com.oracle.truffle.r.runtime.data.RScalar;
 import com.oracle.truffle.r.runtime.data.RString;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
@@ -783,9 +784,16 @@ public class RRuntime {
     /**
      * Java equivalent of GnuR asLogical for use outside Truffle boundary. TODO support for warnings
      */
-    public static byte asLogicalObject(Object objArg) {
-        Object obj = asAbstractVector(objArg);
-        if (obj instanceof RAbstractIntVector) {
+    public static byte asLogicalObject(Object obj) {
+        if (obj instanceof Integer) {
+            return int2logical((int) obj);
+        } else if (obj instanceof Double) {
+            return double2logical((double) obj);
+        } else if (obj instanceof Byte) {
+            return (byte) obj;
+        } else if (obj instanceof String) {
+            return string2logical((String) obj);
+        } else if (obj instanceof RAbstractIntVector) {
             return int2logical(((RAbstractIntVector) obj).getDataAt(0));
         } else if (obj instanceof RAbstractDoubleVector) {
             return double2logical(((RAbstractDoubleVector) obj).getDataAt(0));
@@ -803,9 +811,16 @@ public class RRuntime {
     /**
      * Java equivalent of GnuR asInteger for use outside Truffle boundary. TODO support for warnings
      */
-    public static int asInteger(Object objArg) {
-        Object obj = asAbstractVector(objArg);
-        if (obj instanceof RAbstractIntVector) {
+    public static int asInteger(Object obj) {
+        if (obj instanceof Integer) {
+            return (int) obj;
+        } else if (obj instanceof Double) {
+            return double2int((double) obj);
+        } else if (obj instanceof Byte) {
+            return logical2int((byte) obj);
+        } else if (obj instanceof String) {
+            return string2int((String) obj);
+        } else if (obj instanceof RAbstractIntVector) {
             return ((RAbstractIntVector) obj).getDataAt(0);
         } else if (obj instanceof RAbstractDoubleVector) {
             return double2int(((RAbstractDoubleVector) obj).getDataAt(0));
@@ -856,6 +871,25 @@ public class RRuntime {
         }
     }
 
+    /**
+     * Convert Java boxing classes to {@link RScalar} subclasses, which implement the proper
+     * {@link RAbstractVector} interfaces. This doesn't go through {@link RDataFactory}, but it
+     * increases polymorphism by not using the normal vector classes.
+     */
+    public static Object convertScalarVectors(Object obj) {
+        if (obj instanceof Integer) {
+            return RInteger.valueOf((int) obj);
+        } else if (obj instanceof Double) {
+            return RDouble.valueOf((double) obj);
+        } else if (obj instanceof Byte) {
+            return RLogical.valueOf((byte) obj);
+        } else if (obj instanceof String) {
+            return RString.valueOf((String) obj);
+        } else {
+            return obj;
+        }
+    }
+
     public static boolean isForeignObject(TruffleObject obj) {
         return !(obj instanceof RTypedValue);
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
index a8732baf2dead304863c9507c6435c52e6a99226..eb98e8cdd860a965330f16fb53512c3de75354cc 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
@@ -608,7 +608,6 @@ public final class RDataFactory {
 
     @TruffleBoundary
     private static void reportDataCreated(Object data) {
-        System.out.println("reportDataCreated " + listeners.size() + " " + allocationTracingEnabled);
         if (allocationTracingEnabled) {
             RContext ctx = RContext.getInstance();
             assert ctx != null;