diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java
index a6cc8d2f64441a99abe144cc1b0c4dd40ebc939b..ff350dcc82199c9449763aafb4ec823c97c711e3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java
@@ -13,7 +13,6 @@ package com.oracle.truffle.r.nodes.builtin.base;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asIntegerVector;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.complexValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
@@ -49,8 +48,8 @@ public abstract class APerm extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("a").mustBe(nullValue().not(), RError.Message.FIRST_ARG_MUST_BE_ARRAY);
-        casts.arg("perm").mustBe(numericValue().or(stringValue()).or(complexValue()).or(nullValue())).mapIf(numericValue().or(complexValue()), asIntegerVector());
+        casts.arg("a").mustNotBeNull(RError.Message.FIRST_ARG_MUST_BE_ARRAY);
+        casts.arg("perm").allowNull().mustBe(numericValue().or(stringValue()).or(complexValue())).mapIf(numericValue().or(complexValue()), asIntegerVector());
         casts.arg("resize").mustBe(numericValue().or(logicalValue()), Message.INVALID_LOGICAL, "resize").asLogicalVector().findFirst();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java
index 1c16340d0c36dc69c1f7d718887e478a23c8e071..60f81f5dbcc6e44e3f296eaa0318f523584a0e64 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java
@@ -84,11 +84,9 @@ public abstract class Array extends RBuiltinNode {
     @Override
     protected void createCasts(CastBuilder casts) {
         Function<Object, Object> argType = this::argType;
-        casts.arg("data").mustBe(abstractVectorValue(),
-                        RError.SHOW_CALLER, RError.Message.MUST_BE_VECTOR_BUT_WAS, "data",
-                        argType);
-        casts.arg("dim").asIntegerVector().mustBe(notEmpty(), RError.SHOW_CALLER, RError.Message.CANNOT_BE_LENGTH, "dims", 0);
-        casts.arg("dimnames").shouldBe(instanceOf(RList.class).or(nullValue()), RError.SHOW_CALLER,
+        casts.arg("data").defaultError(RError.SHOW_CALLER, RError.Message.MUST_BE_VECTOR_BUT_WAS, "data", argType).mustBe(abstractVectorValue());
+        casts.arg("dim").defaultError(RError.SHOW_CALLER, RError.Message.CANNOT_BE_LENGTH, "dims", 0).asIntegerVector().mustBe(notEmpty());
+        casts.arg("dimnames").allowNull().shouldBe(instanceOf(RList.class), RError.SHOW_CALLER,
                         RError.Message.GENERIC, "non-list dimnames are disregarded; will be an error in R 3.3.0").mapIf(
                                         instanceOf(RList.class).not(), nullConstant());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java
index 7c29e7beb057ffa40802f9bf1c38f497b40fc028..20b61c1e9c4bc222f8520b032360d290b780279b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java
@@ -47,7 +47,7 @@ public abstract class AsCharacter extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mapIf(instanceOf(RAbstractListVector.class).not(), asStringVector());
+        casts.arg("x").allowNull().mapIf(instanceOf(RAbstractListVector.class).not(), asStringVector());
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsComplex.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsComplex.java
index 964c8bceec1b1198a9d4b2d4a4cc554e722f92a3..56de0ead0465957c4b675379c08bdefe7d3d360e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsComplex.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsComplex.java
@@ -41,7 +41,7 @@ public abstract class AsComplex extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").asComplexVector();
+        casts.arg("x").allowNull().asComplexVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java
index 39780bb2a6ad5b9880a96d7d39422154be6673fe..7f8d5c1015ee42e9828dca78e5eb8f24b4e877e8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java
@@ -41,7 +41,7 @@ public abstract class AsDouble extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").asDoubleVector();
+        casts.arg("x").allowNull().asDoubleVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java
index c6a78959fa4142db09ac12146080ef1d05d2f176..77b77b31f14c03e1309d409685310217626fc0b5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java
@@ -42,7 +42,7 @@ public abstract class AsInteger extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").asIntegerVector();
+        casts.arg("x").allowNull().asIntegerVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java
index d92ed1e1a988451b5bbc6501fb6d855bcb10d436..fbdc14690c61b46e14d132bc7a489abfbd9c28a9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java
@@ -41,7 +41,7 @@ public abstract class AsLogical extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").asLogicalVector();
+        casts.arg("x").allowNull().asLogicalVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsRaw.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsRaw.java
index 1300bfa38b2addff31d700096f857731d464eda8..dafd3a6f8a5ecd8de9ec560f43221edabc0d4b49 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsRaw.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsRaw.java
@@ -41,7 +41,7 @@ public abstract class AsRaw extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").asRawVector();
+        casts.arg("x").allowNull().asRawVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java
index 1af8e0ba9aa15ae52e70af657e5b4e8f90e20ea0..424f4a0ec9181e2ec7f063a50823cb13af4ccf3a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
 import static com.oracle.truffle.r.runtime.RVisibility.OFF;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
@@ -95,7 +94,7 @@ public abstract class Assign extends RBuiltinNode {
     protected void createCasts(CastBuilder casts) {
         casts.arg("x").asStringVector().shouldBe(singleElement(), RError.Message.ONLY_FIRST_VARIABLE_NAME).findFirst(RError.Message.INVALID_FIRST_ARGUMENT);
 
-        casts.arg("envir").mustBe(nullValue().not(), RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(REnvironment.class, RError.Message.INVALID_ARGUMENT, "envir");
+        casts.arg("envir").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(REnvironment.class, RError.Message.INVALID_ARGUMENT, "envir");
 
         // this argument could be made Boolean unless there were AssignFastPath relying upon the
         // byte argument
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AttachFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AttachFunctions.java
index 1b869b0869c1f5221ee47dbfa710707839f7d59b..7aa2a9e377a79c7ff78ff600516a84f1fafb6a78 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AttachFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AttachFunctions.java
@@ -23,7 +23,6 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.RVisibility.OFF;
@@ -55,7 +54,7 @@ public class AttachFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("what").mustBe(instanceOf(REnvironment.class).or(nullValue()).or(instanceOf(RAbstractListVector.class)), RError.Message.ATTACH_BAD_TYPE);
+            casts.arg("what").allowNull().mustBe(instanceOf(REnvironment.class).or(instanceOf(RAbstractListVector.class)), RError.Message.ATTACH_BAD_TYPE);
             casts.arg("pos").mustBe(numericValue(), Message.MUST_BE_INTEGER, "pos").asIntegerVector();
             casts.arg("name").mustBe(stringValue());
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BaseGammaFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BaseGammaFunctions.java
index adb566aeda9e73250d7a5488c51475279161c901..effc12dc4a140b4275b8d7822ef084206ac59b97 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BaseGammaFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BaseGammaFunctions.java
@@ -74,7 +74,7 @@ public class BaseGammaFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue(), RError.Message.NON_NUMERIC_MATH).asDoubleVector();
+            casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue()).asDoubleVector();
         }
 
         @Specialization
@@ -118,7 +118,7 @@ public class BaseGammaFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue(), RError.Message.NON_NUMERIC_MATH).asDoubleVector();
+            casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue()).asDoubleVector();
         }
 
         @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BitwiseFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BitwiseFunctions.java
index 32a6af18214ee275174a356d2d4623277d5cadd1..d114d14909fc1612e7373aa3edb48be16d15599d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BitwiseFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BitwiseFunctions.java
@@ -142,8 +142,8 @@ public class BitwiseFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("a").mustBe(doubleValue().or(integerValue()), RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.AND.name).asIntegerVector();
-            casts.arg("b").mustBe(doubleValue().or(integerValue()), RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.AND.name).asIntegerVector();
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.AND.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+            casts.arg("b").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.AND.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
         }
 
         @Specialization
@@ -164,8 +164,8 @@ public class BitwiseFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("a").mustBe(doubleValue().or(integerValue()), RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.OR.name).asIntegerVector();
-            casts.arg("b").mustBe(doubleValue().or(integerValue()), RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.OR.name).asIntegerVector();
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.OR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+            casts.arg("b").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.OR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
         }
 
         @Specialization
@@ -185,8 +185,8 @@ public class BitwiseFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("a").mustBe(doubleValue().or(integerValue()), RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.XOR.name).asIntegerVector();
-            casts.arg("b").mustBe(doubleValue().or(integerValue()), RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.XOR.name).asIntegerVector();
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.XOR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+            casts.arg("b").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.XOR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
         }
 
         @Specialization
@@ -206,7 +206,7 @@ public class BitwiseFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("a").mustBe(doubleValue().or(integerValue()), RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.SHIFTR.name).asIntegerVector();
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.SHIFTR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
             casts.arg("n").mapIf(stringValue(), asStringVector(), asIntegerVector());
         }
 
@@ -234,8 +234,10 @@ public class BitwiseFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("a").mustBe(doubleValue().or(integerValue()), RError.ROOTNODE, RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.SHIFTL.name).asIntegerVector();
-            casts.arg("n").mapIf(stringValue(), chain(asStringVector()).with(shouldBe(anyValue().not(), RError.SHOW_CALLER, false, RError.Message.NA_INTRODUCED_COERCION)).end(), asIntegerVector());
+            casts.arg("a").defaultError(RError.ROOTNODE, RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.SHIFTL.name).mustBe(
+                            doubleValue().or(integerValue())).asIntegerVector();
+            casts.arg("n").allowNull().mapIf(stringValue(),
+                            chain(asStringVector()).with(shouldBe(anyValue().not(), RError.SHOW_CALLER, false, RError.Message.NA_INTRODUCED_COERCION)).end(), asIntegerVector());
         }
 
         @Specialization
@@ -262,7 +264,7 @@ public class BitwiseFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("a").mustBe(doubleValue().or(integerValue()), RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.NOT.name).asIntegerVector();
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.NOT.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
         }
 
         @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java
index 5fc17758347b2e04013ac321b5451e25c7bd67ec..ad9719fc6246daea404f44b2ee6eeeb28e765947 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java
@@ -62,7 +62,7 @@ public class BrowserFunctions {
         @Override
         protected void createCasts(CastBuilder casts) {
             // TODO: add support for conditions conditions
-            casts.arg("condition").mustBe(nullValue(), RError.Message.GENERIC, "Only NULL conditions currently supported in browser");
+            casts.arg("condition").allowNull().mustBe(anyValue().not(), RError.Message.GENERIC, "Only NULL conditions currently supported in browser");
             casts.arg("expr").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
             casts.arg("skipCalls").asIntegerVector().findFirst(0);
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java
index 6441f318336fdcd7c3cec5a646d2878ee05a6ad4..eddd3c70af0993547e4abfadfa9c69a53b225497 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java
@@ -28,10 +28,10 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.defaultValue
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gt0;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.emptyStringVector;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.RVisibility.OFF;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.IO;
@@ -79,10 +79,11 @@ public abstract class Cat extends RBuiltinNode {
     protected void createCasts(CastBuilder casts) {
         casts.arg("sep").mustBe(stringValue(), RError.Message.INVALID_SEP);
 
-        casts.arg("fill").mustBe(numericValue()).asVector().mustBe(singleElement()).findFirst().mustBe(nullValue().not()).shouldBe(instanceOf(Byte.class).or(instanceOf(Integer.class).and(gt0())),
+        casts.arg("fill").conf(c -> c.allowNull()).mustBe(numericValue()).asVector().mustBe(singleElement()).findFirst().shouldBe(
+                        instanceOf(Byte.class).or(instanceOf(Integer.class).and(gt0())),
                         Message.NON_POSITIVE_FILL).mapIf(logicalValue(), asBoolean(), asInteger());
 
-        casts.arg("labels").map(defaultValue(RDataFactory.createStringVector(0))).mustBe(stringValue()).asStringVector();
+        casts.arg("labels").mapNull(emptyStringVector()).mustBe(stringValue()).asStringVector();
 
         // append is interpreted in the calling closure, but GnuR still checks for NA
         casts.arg("append").asLogicalVector().findFirst().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ceiling.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ceiling.java
index dc3ad505ae91d6137443087c9f7a324a07fedd14..9ea6d639e41d4cb7cd13c94ed6e09b860809b807 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ceiling.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ceiling.java
@@ -22,7 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
 import static com.oracle.truffle.r.runtime.RDispatch.MATH_GROUP_GENERIC;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
@@ -48,7 +48,7 @@ public abstract class Ceiling extends UnaryArithmeticBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mustBe(numericValue(), RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION);
+        casts.arg("x").mustNotBeNull(this, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).asDoubleVector();
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Col.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Col.java
index fdfb7fc3a832adea1877761167956f9836bae5e4..f01f18b8f3f6f998338bafb0c913656ad71cc18a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Col.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Col.java
@@ -42,7 +42,7 @@ public abstract class Col extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("dims").mustBe(nullValue().not().and(integerValue()), RError.Message.MATRIX_LIKE_REQUIRED, "col").asIntegerVector().mustBe(size(2));
+        casts.arg("dims").defaultError(RError.SHOW_CALLER, RError.Message.MATRIX_LIKE_REQUIRED, "col").mustBe(integerValue()).asIntegerVector().mustBe(size(2));
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java
index 761897f79d0795cfbe701b0f57891553f3de442f..a18522b37689d92276fc10e58cf79fae4ef4fcd0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java
@@ -22,7 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.defaultValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.emptyDoubleVector;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
@@ -45,8 +45,8 @@ public abstract class Complex extends RBuiltinNode {
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg("length.out").asIntegerVector().findFirst(Message.INVALID_LENGTH);
-        casts.arg("real").map(defaultValue(RDataFactory.createEmptyDoubleVector())).asDoubleVector();
-        casts.arg("imaginary").map(defaultValue(RDataFactory.createEmptyDoubleVector())).asDoubleVector();
+        casts.arg("real").mapNull(emptyDoubleVector()).asDoubleVector();
+        casts.arg("imaginary").mapNull(emptyDoubleVector()).asDoubleVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConditionFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConditionFunctions.java
index 9e46e7859168825951c07469d325a4a38143e518..3957c5a02abfa8b64f6d1b8adc046841f4d07523 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConditionFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConditionFunctions.java
@@ -12,7 +12,6 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.RErrorHandling.getHandlerStack;
@@ -56,8 +55,8 @@ public class ConditionFunctions {
     public abstract static class AddCondHands extends RBuiltinNode {
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("classes").mustBe(nullValue().or(stringValue())).asStringVector();
-            casts.arg("handlers").mustBe(nullValue().or(instanceOf(RList.class)));
+            casts.arg("classes").allowNull().mustBe(stringValue()).asStringVector();
+            casts.arg("handlers").allowNull().mustBe(instanceOf(RList.class));
             casts.arg("calling").asLogicalVector().findFirst();
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java
index 4f519e17009281861e026bdcf577a533414c85e7..f7d8b0e1da09597aae4fb38fbe33b6cee0e61857 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lte;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notEmpty;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
@@ -156,7 +155,7 @@ public abstract class ConnectionFunctions {
         }
 
         private static void nchars(CastBuilder casts) {
-            casts.arg("nchars").asIntegerVector().mustBe(nullValue().not().and(notEmpty()));
+            casts.arg("nchars").asIntegerVector().mustBe(notEmpty());
         }
 
         private static void useBytes(CastBuilder casts) {
@@ -252,9 +251,9 @@ public abstract class ConnectionFunctions {
             // TODO how to have either a RNull or a String/RStringVector and have the latter coerced
             // to a
             // RAbstractStringVector to avoid the explicit handling in the specialization
-            casts.arg("text").mustBe(nullValue().or(stringValue()));
+            casts.arg("text").allowNull().mustBe(stringValue());
             Casts.open(casts).mustBe(equalTo("").or(equalTo("r").or(equalTo("w").or(equalTo("a")))), RError.Message.UNSUPPORTED_MODE);
-            casts.arg("env").mustBe(nullValue().not(), RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
+            casts.arg("env").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
             casts.arg("encoding").asIntegerVector().findFirst().notNA();
         }
 
@@ -529,7 +528,7 @@ public abstract class ConnectionFunctions {
     public abstract static class WriteLines extends InternalCloseHelper {
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("text").asStringVector().mustBe(nullValue().not().and(instanceOf(RAbstractStringVector.class)));
+            casts.arg("text").asStringVector().mustBe(instanceOf(RAbstractStringVector.class));
             Casts.connection(casts);
             casts.arg("sep").asStringVector().findFirst();
             Casts.useBytes(casts);
@@ -572,7 +571,7 @@ public abstract class ConnectionFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("data").asStringVector().mustBe(nullValue().not().and(instanceOf(RAbstractStringVector.class)));
+            casts.arg("data").asStringVector().mustBe(instanceOf(RAbstractStringVector.class));
             Casts.connection(casts);
             casts.arg("newLine").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("type").asIntegerVector().findFirst();
@@ -660,7 +659,7 @@ public abstract class ConnectionFunctions {
             casts.arg("object").asStringVector();
             casts.arg("con").mustBe(instanceOf(RConnection.class).or(instanceOf(RAbstractRawVector.class)));
             Casts.nchars(casts);
-            casts.arg("sep").mustBe(stringValue().or(nullValue()));
+            casts.arg("sep").allowNull().mustBe(stringValue());
             Casts.useBytes(casts);
         }
 
@@ -997,7 +996,7 @@ public abstract class ConnectionFunctions {
         @Override
         protected void createCasts(CastBuilder casts) {
             // TODO atomic, i.e. not RList or RExpression
-            casts.arg("object").asVector().mustBe(nullValue().not().and(instanceOf(RAbstractVector.class)));
+            casts.arg("object").asVector().mustBe(instanceOf(RAbstractVector.class));
             Casts.connection(casts);
             size(casts);
             swap(casts);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java
index 45c06fb0744976a153d2169e18108c22aa38914e..13d45c4cab08e9efbea2a8de9ade32c5b9c8d57c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java
@@ -46,7 +46,7 @@ public abstract class Crossprod extends RBuiltinNode {
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg("x").mustBe(numericValue().or(complexValue()), RError.ROOTNODE, RError.Message.NUMERIC_COMPLEX_MATRIX_VECTOR);
-        casts.arg("y").mustBe(nullValue().or(numericValue()).or(complexValue()), RError.ROOTNODE, RError.Message.NUMERIC_COMPLEX_MATRIX_VECTOR);
+        casts.arg("y").defaultError(RError.ROOTNODE, RError.Message.NUMERIC_COMPLEX_MATRIX_VECTOR).allowNull().mustBe(numericValue().or(complexValue()));
     }
 
     private Object matMult(Object op1, Object op2) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMax.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMax.java
index 872c30682870f76dfe1809bae6033b5a2ca4b094..edf8441b58c47ee9bad392bd698d4bc1c72247d7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMax.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMax.java
@@ -47,7 +47,8 @@ public abstract class CumMax extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mustBe(complexValue().not(), RError.Message.CUMMAX_UNDEFINED_FOR_COMPLEX).mapIf(integerValue().or(logicalValue()), asIntegerVector(), asDoubleVector());
+        casts.arg("x").allowNull().mustBe(complexValue().not(), RError.Message.CUMMAX_UNDEFINED_FOR_COMPLEX).mapIf(integerValue().or(logicalValue()), asIntegerVector(),
+                        asDoubleVector());
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMin.java
index f0a1f1439b96b46b6e64cde014ba7948e4f6adaf..a1da7b792e40c8abb45fa505b7b76c03946a281f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMin.java
@@ -47,7 +47,8 @@ public abstract class CumMin extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mustBe(complexValue().not(), RError.Message.CUMMIN_UNDEFINED_FOR_COMPLEX).mapIf(integerValue().or(logicalValue()), asIntegerVector(), asDoubleVector());
+        casts.arg("x").allowNull().mustBe(complexValue().not(), RError.Message.CUMMIN_UNDEFINED_FOR_COMPLEX).mapIf(integerValue().or(logicalValue()), asIntegerVector(),
+                        asDoubleVector());
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java
index 3411fd0b41182c5fef1ec000cb22793c7694b3c9..377b8a51794a1d99c72a5750e0d856511f23d36e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java
@@ -51,7 +51,7 @@ public abstract class CumProd extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mapIf(integerValue().or(logicalValue()), asIntegerVector(), chain(mapIf(complexValue().not(), asDoubleVector())).end());
+        casts.arg("x").allowNull().mapIf(integerValue().or(logicalValue()), asIntegerVector(), chain(mapIf(complexValue().not(), asDoubleVector())).end());
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java
index 40f8f3c57d18b265f2a4cdaf3db001790f36cc10..9e259d23d2ea5fb214c683a553714afbbc22be3c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java
@@ -64,7 +64,7 @@ public abstract class CumSum extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mapIf(integerValue().or(logicalValue()), asIntegerVector(), chain(mapIf(complexValue().not(), asDoubleVector())).end());
+        casts.arg("x").allowNull().mapIf(integerValue().or(logicalValue()), asIntegerVector(), chain(mapIf(complexValue().not(), asDoubleVector())).end());
     }
 
     @Specialization
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 dbf4ae312339bcad43447c707c1947a08746efff..d1d40080d1f9b056a2bd6b11c8c87fbe41d85c44 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
@@ -11,9 +11,9 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.defaultValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.emptyDoubleVector;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notEmpty;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_STATE;
@@ -140,7 +140,7 @@ public class DatePOSIXFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").map(defaultValue(RDataFactory.createEmptyDoubleVector())).asDoubleVector();
+            casts.arg("x").mapNull(emptyDoubleVector()).asDoubleVector();
         }
 
         @Specialization
@@ -176,7 +176,7 @@ public class DatePOSIXFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").map(defaultValue(RDataFactory.createEmptyDoubleVector())).asDoubleVector(true, false, false);
+            casts.arg("x").mapNull(emptyDoubleVector()).asDoubleVector(true, false, false);
             casts.arg("tz").asStringVector().findFirst("");
         }
 
@@ -333,7 +333,7 @@ public class DatePOSIXFunctions {
         @Override
         protected void createCasts(CastBuilder casts) {
             casts.arg("x").mustBe(RAbstractListVector.class);
-            casts.arg("format").mustBe(nullValue().not()).asStringVector().mustBe(notEmpty());
+            casts.arg("format").asStringVector().mustBe(notEmpty());
             casts.arg("usetz").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
         }
 
@@ -390,9 +390,9 @@ public class DatePOSIXFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").map(defaultValue(RDataFactory.createEmptyStringVector())).asStringVector();
-            casts.arg("format").map(defaultValue(RDataFactory.createEmptyStringVector())).asStringVector();
-            casts.arg("tz").map(defaultValue(RDataFactory.createEmptyStringVector())).asStringVector();
+            casts.arg("x").mapNull(emptyStringVector()).asStringVector();
+            casts.arg("format").mapNull(emptyStringVector()).asStringVector();
+            casts.arg("tz").mapNull(emptyStringVector()).asStringVector();
         }
 
         @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DelayedAssign.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DelayedAssign.java
index 1c12e42ec82f04aaf12ebecf895b9cc553fa94dc..aee8c55217c12109347334911becede38d068c4a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DelayedAssign.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DelayedAssign.java
@@ -50,8 +50,8 @@ public abstract class DelayedAssign extends RBuiltinNode {
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg("x").mustBe(stringValue()).asStringVector().mustBe(notEmpty(), RError.Message.INVALID_FIRST_ARGUMENT).findFirst();
-        casts.arg("eval.env").mustBe(nullValue().not(), RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
-        casts.arg("assign.env").mustBe(nullValue().not(), RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
+        casts.arg("eval.env").mustNotBeNull(RError.SHOW_CALLER, RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
+        casts.arg("assign.env").mustNotBeNull(RError.SHOW_CALLER, RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java
index eba631239d2e1986450e733ba9c64c1cbf2950e1..b8130992c80cc11e3786415aff64f48aa678dd0d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java
@@ -39,7 +39,7 @@ public abstract class Diag extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mapIf(complexValue().not(), asDoubleVector());
+        casts.arg("x").allowNull().mapIf(complexValue().not(), asDoubleVector());
 
         casts.arg("nrow").asIntegerVector().findFirst().mustBe(notIntNA(), Message.INVALID_LARGE_NA_VALUE, "nrow").mustBe(gte0(), Message.INVALID_NEGATIVE_VALUE, "nrow");
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DuplicatedFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DuplicatedFunctions.java
index eea62355abc09e830a188d4c2697a12f89d725eb..24acef240f44bff271e3b80a8e4bcb1df53537db 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DuplicatedFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DuplicatedFunctions.java
@@ -11,7 +11,8 @@
 
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.emptyList;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
@@ -33,8 +34,8 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.nodes.DuplicationHelper;
 
 public class DuplicatedFunctions {
@@ -47,7 +48,8 @@ public class DuplicatedFunctions {
 
         protected void casts(CastBuilder casts) {
             // these are similar to those in DuplicatedFunctions.java
-            casts.arg("x").mustBe(nullValue().or(abstractVectorValue()), RError.SHOW_CALLER, RError.Message.APPLIES_TO_VECTORS,
+            casts.arg("x").mapNull(emptyList()).mustBe(abstractVectorValue(), RError.SHOW_CALLER,
+                            RError.Message.APPLIES_TO_VECTORS,
                             "duplicated()").asVector();
             // not much more can be done for incomparables as it is either a vector of incomparable
             // values or a (single) logical value
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodingFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodingFunctions.java
index 46904a1fd59f1e7f47277ddfa28653d155eb53fc..d8c5f44aa8a65b67506736c8bcf80556bba2d8f8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodingFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodingFunctions.java
@@ -56,11 +56,10 @@ public class EncodingFunctions {
     public abstract static class SetEncoding extends RBuiltinNode {
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.CHAR_VEC_ARGUMENT);
+            casts.arg("x").defaultError(RError.SHOW_CALLER, RError.Message.CHAR_VEC_ARGUMENT).mustBe(stringValue());
             // asStringVector is required for notEmpty() to receive a proper type in case of scalars
-            casts.arg("value").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.GENERIC, "a character vector 'value' expected").asStringVector().mustBe(notEmpty(), RError.SHOW_CALLER,
-                            RError.Message.GENERIC,
-                            "'value' must be of positive length");
+            casts.arg("value").defaultError(RError.SHOW_CALLER, RError.Message.GENERIC, "a character vector 'value' expected").mustBe(stringValue()).asStringVector().mustBe(notEmpty(),
+                            RError.SHOW_CALLER, RError.Message.GENERIC, "'value' must be of positive length");
         }
 
         @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
index c2954304c330a0e847c682c9bc73c9ff25c9287d..5f185fed46198208a9ea5e0f37c60f83276e33d0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
@@ -113,7 +113,7 @@ public class FileFunctions {
         @Override
         protected void createCasts(CastBuilder casts) {
             casts.arg("file1").mustBe(stringValue()).asStringVector();
-            casts.arg("file1").mustBe(stringValue()).asStringVector();
+            casts.arg("file2").mustBe(stringValue()).asStringVector();
         }
 
         @Specialization
@@ -566,7 +566,7 @@ public class FileFunctions {
         @Override
         protected void createCasts(CastBuilder casts) {
             casts.arg("path").mustBe(stringValue()).asStringVector();
-            casts.arg("pattern").mustBe(stringValue().or(nullValue()));
+            casts.arg("pattern").allowNull().mustBe(stringValue());
             casts.arg("all.files").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("full.names").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("recursive").asLogicalVector().findFirst().notNA().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Floor.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Floor.java
index 5dc2785893d1cbbbab0ea56af09e4deb7102b9c5..5cfb52fd805c984aa4d327cd58813867f3bfd328 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Floor.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Floor.java
@@ -22,7 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
 import static com.oracle.truffle.r.runtime.RDispatch.MATH_GROUP_GENERIC;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
@@ -48,7 +48,7 @@ public abstract class Floor extends UnaryArithmeticBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mustBe(numericValue(), RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION);
+        casts.arg("x").mustNotBeNull(this, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).asDoubleVector();
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetText.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetText.java
index 6af408b6bee5e99998275a8270665da738a59c83..be2ae78d8794067dda33480979066cf13f8a8322 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetText.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetText.java
@@ -38,7 +38,7 @@ public abstract class GetText extends RBuiltinNode {
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg("domain").asStringVector().findFirst("");
-        casts.arg("args").asStringVector();
+        casts.arg("args").allowNull().asStringVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
index 4359d6faa7feb74f933cf8ebfb413b8c95a84535..2f923ca2d45aa15ebd99ff28b0ce090932cceb9c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
@@ -12,7 +12,6 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.RVisibility.OFF;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
@@ -147,10 +146,10 @@ public class HiddenInternalFunctions {
     public abstract static class ImportIntoEnv extends RBuiltinNode {
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("impenv").mustBe(nullValue().not(), RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class), RError.Message.BAD_ENVIRONMENT, "import");
-            casts.arg("expenv").mustBe(nullValue().not(), RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class), RError.Message.BAD_ENVIRONMENT, "import");
-            casts.arg("impnames").mustBe(stringValue(), RError.Message.INVALID_ARGUMENT, "names").asStringVector();
-            casts.arg("expnames").mustBe(stringValue(), RError.Message.INVALID_ARGUMENT, "names").asStringVector();
+            casts.arg("impenv").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class), RError.Message.BAD_ENVIRONMENT, "import");
+            casts.arg("impnames").defaultError(RError.Message.INVALID_ARGUMENT, "names").mustBe(stringValue()).asStringVector();
+            casts.arg("expenv").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class), RError.Message.BAD_ENVIRONMENT, "import");
+            casts.arg("expnames").defaultError(RError.Message.INVALID_ARGUMENT, "names").mustBe(stringValue(), RError.Message.INVALID_ARGUMENT, "names").asStringVector();
         }
 
         @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IConv.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IConv.java
index e50baf1fcb93c6a6deabeefe515c403a9c5c64e0..2d1c2f2c6ad9664eedbbc5159ecc3d7cb194ca83 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IConv.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IConv.java
@@ -43,11 +43,9 @@ public abstract class IConv extends RBuiltinNode {
     protected void createCasts(CastBuilder casts) {
         casts.arg("x").mustBe(stringValue(), RError.NO_CALLER, RError.Message.NOT_CHARACTER_VECTOR, "x");
         // with default error message, NO_CALLER does not work
-        casts.arg("from").mustBe(stringValue(), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "from").asStringVector().mustBe(size(1), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT,
-                        "from");
-        casts.arg("to").mustBe(stringValue(), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "to").asStringVector().mustBe(size(1), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT,
-                        "to");
-        casts.arg("sub").mustBe(stringValue(), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "sub").asStringVector().mustBe(size(1), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "sub");
+        casts.arg("from").defaultError(RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "from").mustBe(stringValue()).asStringVector().mustBe(size(1));
+        casts.arg("to").defaultError(RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "to").mustBe(stringValue()).asStringVector().mustBe(size(1));
+        casts.arg("sub").defaultError(RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "sub").mustBe(stringValue()).asStringVector().mustBe(size(1));
         casts.arg("mark").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
         casts.arg("toRaw").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToBits.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToBits.java
index 20ca4fe14472a3f76708eb33ee49de597aa2e3a5..9b65d700b6a7e99b15d7b2ac17a87b9af8f28c56 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToBits.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToBits.java
@@ -39,7 +39,7 @@ public abstract class IntToBits extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").asIntegerVector();
+        casts.arg("x").allowNull().asIntegerVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
index 87b2f73c140d235495c3bed78853de0014c771aa..63e904fc908f03dc0c8c3e977357e4607d3d754e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
@@ -72,7 +71,7 @@ public class IsTypeFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").mustBe(missingValue().not(), RError.Message.ARGUMENT_MISSING, "x");
+            casts.arg("x").conf(c -> c.allowNull().mustNotBeMissing(null, RError.Message.ARGUMENT_MISSING, "x"));
         }
 
     }
@@ -476,7 +475,7 @@ public class IsTypeFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").mustBe(missingValue().not(), RError.Message.ARGUMENT_MISSING, "x");
+            casts.arg("x").conf(c -> c.allowNull().mustNotBeMissing(null, RError.Message.ARGUMENT_MISSING, "x"));
             casts.arg("mode").defaultError(this, RError.Message.INVALID_ARGUMENT, "mode").mustBe(stringValue()).asStringVector().mustBe(size(1));
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lengths.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lengths.java
index 980677ce798c872432de700cd3341a3561779b2a..1911c82d4c157a6142f31df3a1b903f2121a5f72 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lengths.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lengths.java
@@ -23,7 +23,6 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.RError.Message.INVALID_VALUE;
@@ -56,7 +55,7 @@ public abstract class Lengths extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mustBe(abstractVectorValue().or(nullValue()), X_LIST_ATOMIC);
+        casts.arg("x").defaultError(X_LIST_ATOMIC).allowNull().mustBe(abstractVectorValue());
         casts.arg("use.names").mustBe(numericValue(), INVALID_VALUE, "USE.NAMES").asLogicalVector().findFirst().map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LoadSaveFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LoadSaveFunctions.java
index ac1c513d6958b6a8a905b90bede125b0a218a468..1667cb57214e008f159f6c76bb50e95fb9a146a0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LoadSaveFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LoadSaveFunctions.java
@@ -57,7 +57,7 @@ public class LoadSaveFunctions {
         @Override
         protected void createCasts(CastBuilder casts) {
             casts.arg("con").mustBe(instanceOf(RConnection.class));
-            casts.arg("envir").mustBe(nullValue().not(), RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
+            casts.arg("envir").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
             casts.arg("verbose").asLogicalVector().findFirst().map(toBoolean());
         }
 
@@ -113,7 +113,7 @@ public class LoadSaveFunctions {
         @Override
         protected void createCasts(CastBuilder casts) {
             casts.arg("file").mustBe(stringValue()).asStringVector().mustBe(notEmpty(), RError.Message.FIRST_ARGUMENT_NOT_FILENAME).findFirst();
-            casts.arg("envir").mustBe(nullValue().not(), RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
+            casts.arg("envir").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
         }
 
         private static final int R_MAGIC_EMPTY = 999;
@@ -193,8 +193,8 @@ public class LoadSaveFunctions {
             casts.arg("list").mustBe(stringValue()).asStringVector().mustBe(notEmpty(), RError.Message.FIRST_ARGUMENT_NOT_CHARVEC).findFirst();
             casts.arg("con").mustBe(instanceOf(RConnection.class));
             casts.arg("ascii").mustBe(logicalValue(), RError.Message.ASCII_NOT_LOGICAL);
-            casts.arg("version").mustBe(nullValue().or(integerValue()));
-            casts.arg("environment").mustBe(nullValue().not(), RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
+            casts.arg("version").allowNull().mustBe(integerValue());
+            casts.arg("environment").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
             casts.arg("eval.promises").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeNames.java
index 608da437d082ded06b7b0f36170292c617717754..17ff7a961b43aa354e83786301eea5db379826ab 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeNames.java
@@ -48,7 +48,7 @@ public abstract class MakeNames extends RBuiltinNode {
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg("names").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.NON_CHARACTER_NAMES);
-        casts.arg("allow_").asLogicalVector().findFirst(RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "allow_").mustBe(notLogicalNA(), RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "allow_");
+        casts.arg("allow_").defaultError(RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "allow_").asLogicalVector().findFirst().mustBe(notLogicalNA());
     }
 
     @TruffleBoundary
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeUnique.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeUnique.java
index f00beccacd6bb2b30b1e28a5c6dd2e6a207a19c7..a0619c782abdbdcd704b8492c8999ce45b8ec0e2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeUnique.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeUnique.java
@@ -47,7 +47,7 @@ public abstract class MakeUnique extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("names").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.NOT_CHARACTER_VECTOR, "names");
+        casts.arg("names").defaultError(RError.SHOW_CALLER, RError.Message.NOT_CHARACTER_VECTOR, "names").mustBe(stringValue());
         casts.arg("sep").defaultError(RError.SHOW_CALLER, RError.Message.MUST_BE_STRING, "sep").mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
 
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mapply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mapply.java
index d9e462d2389cd15358294cb570e2e5822d2bff83..ac7f1d3e0544819c57ddde5acf947573baac76bd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mapply.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mapply.java
@@ -73,7 +73,7 @@ public abstract class Mapply extends RBuiltinNode {
         casts.arg("FUN").mustBe(instanceOf(RFunction.class));
         casts.arg("dots").mustBe(instanceOf(RAbstractListVector.class));
         // if we could map to an empty list, we could get rid of an additional specialization
-        casts.arg("MoreArgs").mustBe(nullValue().or(instanceOf(RAbstractListVector.class)));
+        casts.arg("MoreArgs").allowNull().mustBe(instanceOf(RAbstractListVector.class));
     }
 
     protected static final class ElementNode extends Node {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java
index c08dac062a534ae42c95cc34eed11ec82d8cd89a..f9fb808fb54480931f2f767d0e28a8609419e739 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java
@@ -23,7 +23,6 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
@@ -70,7 +69,7 @@ public abstract class Matrix extends RBuiltinNode {
         casts.arg("nrow").asIntegerVector().findFirst(RError.Message.NON_NUMERIC_MATRIX_EXTENT);
         casts.arg("ncol").asIntegerVector().findFirst(RError.Message.NON_NUMERIC_MATRIX_EXTENT);
         casts.arg("byrow").asLogicalVector().findFirst().map(toBoolean());
-        casts.arg("dimnames").mustBe(nullValue().or(instanceOf(RAbstractListVector.class)));
+        casts.arg("dimnames").allowNull().mustBe(instanceOf(RAbstractListVector.class));
         casts.arg("missingNr").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("missingNc").asLogicalVector().findFirst().map(toBoolean());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java
index 6f78bad2766e5866b55b01e2188e8cd499db806f..562f6b4ac4bf2a8f79bd85255959d01508412b70 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java
@@ -49,7 +49,7 @@ public abstract class NChar extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mapIf(Predef.integerValue(), asIntegerVector(), asStringVector(true, false, false));
+        casts.arg("x").allowNull().mapIf(Predef.integerValue(), asIntegerVector(), asStringVector(true, false, false));
         casts.arg("type").asStringVector().findFirst();
         casts.arg("allowNA").asLogicalVector().findFirst(RRuntime.LOGICAL_TRUE).map(toBoolean());
         casts.arg("keepNA").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NGetText.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NGetText.java
index 7ae86c1133e33980d7aaf413aa92d7bec032a94e..3756b5ba7cf1637a6a183d0d96331197eb16154c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NGetText.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NGetText.java
@@ -23,7 +23,6 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte0;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
@@ -43,9 +42,9 @@ public abstract class NGetText extends RBuiltinNode {
     protected void createCasts(CastBuilder casts) {
         casts.arg("n").asIntegerVector().findFirst().mustBe(gte0());
 
-        casts.arg("msg1").defaultError(RError.Message.MUST_BE_STRING, "msg1").mustBe(nullValue().not().and(stringValue())).asStringVector().mustBe(singleElement()).findFirst();
+        casts.arg("msg1").defaultError(RError.Message.MUST_BE_STRING, "msg1").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
 
-        casts.arg("msg2").defaultError(RError.Message.MUST_BE_STRING, "msg2").mustBe(nullValue().not().and(stringValue())).asStringVector().mustBe(singleElement()).findFirst();
+        casts.arg("msg2").defaultError(RError.Message.MUST_BE_STRING, "msg2").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
 
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java
index 03a1d92243a754ff346a19caf9acf344ecc16d13..a9091fd271327c427cb91eedb0eb5fc797462b45 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java
@@ -41,7 +41,7 @@ public abstract class NZChar extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").asStringVector();
+        casts.arg("x").allowNull().asStringVector();
         casts.arg("keepNA").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NumericalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NumericalFunctions.java
index e543390812c6ecd082696cbb250240082d2793d9..b955f976259a0570876ef29af61ae0c96e28c07f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NumericalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NumericalFunctions.java
@@ -64,7 +64,7 @@ public class NumericalFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").mustBe(numericValue().or(complexValue()), RError.Message.NON_NUMERIC_MATH);
+            casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(numericValue().or(complexValue()));
         }
 
         @Override
@@ -107,7 +107,7 @@ public class NumericalFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("z").mustBe(numericValue().or(complexValue()), RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION);
+            casts.arg("z").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
         @Override
@@ -150,7 +150,7 @@ public class NumericalFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("z").mustBe(numericValue().or(complexValue()), RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION);
+            casts.arg("z").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
         @Override
@@ -193,7 +193,7 @@ public class NumericalFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("z").mustBe(numericValue().or(complexValue()), RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION);
+            casts.arg("z").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
         @Override
@@ -226,7 +226,7 @@ public class NumericalFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("z").mustBe(numericValue().or(complexValue()), RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION);
+            casts.arg("z").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
         @Override
@@ -269,7 +269,7 @@ public class NumericalFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").mustBe(numericValue(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN);
+            casts.arg("x").defaultError(RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue());
         }
 
         @Override
@@ -298,7 +298,7 @@ public class NumericalFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").mustBe(numericValue().or(complexValue()), RError.Message.UNIMPLEMENTED_COMPLEX_FUN);
+            casts.arg("x").defaultError(RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue().or(complexValue()));
         }
 
         @Override
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java
index e07c62fc6864be8d98a9b1f85987947533f8dcfc..f5487620db0fb63a21abd652f71710e0cf582d99 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java
@@ -200,7 +200,7 @@ public class OptionsFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.MUST_BE_STRING, "x").asStringVector().findFirst();
+            casts.arg("x").defaultError(RError.SHOW_CALLER, RError.Message.MUST_BE_STRING, "x").mustBe(stringValue()).asStringVector().findFirst();
         }
 
         @TruffleBoundary
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMatch.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMatch.java
index c130b43d8d06a782bd9db21a384281ff2a56f34b..4f841fb44d50e02358d9a6f652bc4736735e83ee 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMatch.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMatch.java
@@ -23,7 +23,6 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.constant;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
@@ -48,8 +47,8 @@ public abstract class PMatch extends RBuiltinNode {
     protected void createCasts(CastBuilder casts) {
         casts.arg("x").asStringVector();
         casts.arg("table").asStringVector();
-        casts.arg("nomatch").mapIf(nullValue(), constant(RRuntime.INT_NA)).asIntegerVector();
-        casts.arg("duplicates.ok").mustBe(nullValue().not().and(numericValue())).asLogicalVector().findFirst().map(toBoolean());
+        casts.arg("nomatch").mapNull(constant(RRuntime.INT_NA)).asIntegerVector();
+        casts.arg("duplicates.ok").mustBe(numericValue()).asLogicalVector().findFirst().map(toBoolean());
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java
index 529f8b30e4828ae8c6c83af2e24569d1b3a01279..3adc51a5ec5db692318cfb07747cce071d20ff08 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java
@@ -53,8 +53,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.conn.ConnectionSupport;
 import com.oracle.truffle.r.runtime.conn.RConnection;
 import com.oracle.truffle.r.runtime.conn.StdConnections;
-import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.Engine.ParseException;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RLanguage;
@@ -104,9 +104,9 @@ public abstract class Parse extends RBuiltinNode {
         // Note: string is captured by the R wrapper and transformed to a file, other types not
         casts.arg("conn").mustBe(RConnection.class, MUST_BE_STRING_OR_CONNECTION, "file");
         casts.arg("n").asIntegerVector().findFirst(RRuntime.INT_NA).mapIf(RRuntime::isNA, constant(-1));
-        casts.arg("text").mapIf(nullValue().not(), asStringVector());
+        casts.arg("text").allowNull().asStringVector();
         casts.arg("prompt").asStringVector().findFirst("?");
-        casts.arg("encoding").mustBe(nullValue().not().and(stringValue())).asStringVector().findFirst();
+        casts.arg("encoding").mustBe(stringValue()).asStringVector().findFirst();
     }
 
     @TruffleBoundary
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java
index 5c1da7163a97b14f3389fd99a8999d97073d117a..f0b6fbeeddcba28d048025e24784dca2676fbc9a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
@@ -66,8 +65,8 @@ public abstract class Paste extends RBuiltinNode {
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg(0).mustBe(RAbstractListVector.class);
-        casts.arg("sep").mustBe(nullValue().not()).asStringVector().findFirst(Message.INVALID_SEPARATOR);
-        casts.arg("collapse").mustBe(Predef.stringValue().or(Predef.nullValue())).mapIf(Predef.stringValue(), Predef.findFirst().stringElement());
+        casts.arg("sep").asStringVector().findFirst(Message.INVALID_SEPARATOR);
+        casts.arg("collapse").allowNull().mustBe(Predef.stringValue()).asStringVector().findFirst();
     }
 
     /**
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PathExpand.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PathExpand.java
index af24c598864bfd084284228160ea702ecd45106c..640b323010095b81810560ba398ca39a4b9028ea 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PathExpand.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PathExpand.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.IO;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
@@ -41,7 +40,7 @@ public abstract class PathExpand extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("path").mustBe(nullValue().not().and(stringValue()));
+        casts.arg("path").mustBe(stringValue());
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java
index aa6d793bfb46142f81652a8c8b18d9607aa29d03..7a7f477b0aaa47dddefcb02f08759ca27f5d8776 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java
@@ -22,16 +22,10 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asIntegerVector;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asStringVector;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.chain;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.findFirst;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lte;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.mustBe;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notIntNA;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.RVisibility.OFF;
@@ -70,21 +64,17 @@ public class PrintFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("digits").mapIf(nullValue().not(), chain(asIntegerVector()).with(findFirst().integerElement()).with(mustBe(notIntNA(), false)).with(
-                            mustBe(gte(Format.R_MIN_DIGITS_OPT).and(lte(Format.R_MAX_DIGITS_OPT)), false)).end());
+            casts.arg("digits").allowNull().asIntegerVector().findFirst().mustBe(notIntNA()).mustBe(gte(Format.R_MIN_DIGITS_OPT).and(lte(Format.R_MAX_DIGITS_OPT)));
 
             casts.arg("quote").asLogicalVector().findFirst().notNA().map(toBoolean());
 
-            casts.arg("na.print").defaultError(RError.Message.INVALID_NA_PRINT_SPEC).mapIf(nullValue().not(),
-                            chain(mustBe(stringValue(), false)).with(asStringVector()).with(findFirst().stringElement()).end());
+            casts.arg("na.print").defaultError(RError.Message.INVALID_NA_PRINT_SPEC).allowNull().mustBe(stringValue()).asStringVector().findFirst();
 
-            casts.arg("print.gap").defaultError(RError.Message.GAP_MUST_BE_NON_NEGATIVE).mapIf(nullValue().not(),
-                            chain(asIntegerVector()).with(findFirst().integerElement()).with(mustBe(notIntNA(),
-                                            false)).with(mustBe(gte(0), false)).end());
+            casts.arg("print.gap").defaultError(RError.Message.GAP_MUST_BE_NON_NEGATIVE).allowNull().asIntegerVector().findFirst().mustBe(notIntNA()).mustBe(gte(0));
 
             casts.arg("right").defaultError(RError.Message.INVALID_ARGUMENT, "right").asLogicalVector().findFirst().notNA().map(toBoolean());
 
-            casts.arg("max").mapIf(nullValue().not(), chain(asIntegerVector()).with(findFirst().integerElement()).with(mustBe(notIntNA(), false)).with(mustBe(gte(0), false)).end());
+            casts.arg("max").allowNull().asIntegerVector().findFirst().mustBe(notIntNA()).mustBe(gte(0));
 
             casts.arg("useSource").defaultError(RError.Message.INVALID_ARGUMENT, "useSource").asLogicalVector().findFirst().notNA().map(toBoolean());
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quantifier.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quantifier.java
index 0b394130a6bcf3c2843144f35926cd99982ea017..80a9bc80086da484cc60f2ace5e73e0aacafe554 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quantifier.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quantifier.java
@@ -24,7 +24,6 @@ package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 
 import java.util.function.Function;
@@ -57,8 +56,6 @@ public abstract class Quantifier extends RBuiltinNode {
     @Child private TypeofNode typeofNode = com.oracle.truffle.r.nodes.unary.TypeofNodeGen.create();
     private final Function<Object, String> argTypeName = arg -> typeofNode.execute(arg).getName();
 
-    private final CastBuilder argCastBuilder = new CastBuilder();
-
     @Children private final CastNode[] argCastNodes = new CastNode[MAX_CACHED_LENGTH];
 
     @Override
@@ -72,8 +69,9 @@ public abstract class Quantifier extends RBuiltinNode {
     }
 
     private void createArgCast(int index) {
-        argCastBuilder.arg(index).shouldBe(nullValue().or(integerValue()).or(logicalValue()), RError.Message.COERCING_ARGUMENT, argTypeName, "logical").asLogicalVector();
-        argCastNodes[index] = insert(argCastBuilder.getCasts()[index]);
+        CastBuilder argCastBuilder = new CastBuilder();
+        argCastBuilder.arg(0).allowNull().shouldBe(integerValue().or(logicalValue()), RError.Message.COERCING_ARGUMENT, argTypeName, "logical").asLogicalVector();
+        argCastNodes[index] = insert(argCastBuilder.getCasts()[0]);
     }
 
     protected boolean emptyVectorResult() {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RNGFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RNGFunctions.java
index e37be4dadf0d12bc2f96da400b32bfc3eb894bc9..a7050b0bb8120a1b4c932419e4ce943c60ee6293 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RNGFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RNGFunctions.java
@@ -22,11 +22,8 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asIntegerVector;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.chain;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.anyValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.constant;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.findFirst;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.RError.SHOW_CALLER;
@@ -54,10 +51,11 @@ public class RNGFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("seed").mustBe(numericValue().or(nullValue()), SHOW_CALLER, SEED_NOT_VALID_INT).mapIf(nullValue().not(), chain(asIntegerVector()).with(findFirst().stringElement()).end());
+            casts.arg("seed").allowNull().mustBe(numericValue(), SHOW_CALLER, SEED_NOT_VALID_INT).asIntegerVector().findFirst();
             Casts.kindInteger(casts, "kind", INVALID_ARGUMENT, "kind");
             // TODO: implement normal.kind specializations with String
-            casts.arg("normal.kind").mustBe(stringValue().or(nullValue()), SHOW_CALLER, INVALID_NORMAL_TYPE_IN_RGNKIND).mustBe(nullValue(), UNIMPLEMENTED_TYPE_IN_FUNCTION, "String", "set.seed");
+            casts.arg("normal.kind").allowNull().mustBe(stringValue(), SHOW_CALLER, INVALID_NORMAL_TYPE_IN_RGNKIND).mustBe(anyValue().not(), UNIMPLEMENTED_TYPE_IN_FUNCTION, "String",
+                            "set.seed");
         }
 
         @SuppressWarnings("unused")
@@ -103,9 +101,7 @@ public class RNGFunctions {
 
     private static final class Casts {
         public static void kindInteger(CastBuilder casts, String name, Message error, Object... messageArgs) {
-            casts.arg(name).mustBe(nullValue().or(numericValue()), SHOW_CALLER, error, messageArgs).mapIf(nullValue().not(), chain(asIntegerVector()).with(findFirst().stringElement()).end()).mapIf(
-                            nullValue(),
-                            constant(RRNG.NO_KIND_CHANGE));
+            casts.arg(name).mapNull(constant(RRNG.NO_KIND_CHANGE)).mustBe(numericValue(), SHOW_CALLER, error, messageArgs).asIntegerVector().findFirst();
         }
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java
index 813c92a2c95ad86f5efadc27eda2eb5ba3554869..2d9f66c7dec0eed51f9b65ea35d070586a56ca93 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java
@@ -54,8 +54,8 @@ public abstract class ReadDCF extends RBuiltinNode {
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg("conn").mustBe(RConnection.class);
-        casts.arg("fields").mapIf(nullValue(), asVector(false)).asStringVector();
-        casts.arg("keepwhite").mapIf(nullValue(), asVector(false)).asStringVector();
+        casts.arg("fields").mapNull(emptyStringVector()).asStringVector();
+        casts.arg("keepwhite").mapNull(emptyStringVector()).asStringVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java
index ba423dae3cbafc423b481033a8fb9b51cba8348a..ffb5e45e55bcce6a44c61cb458651661a169fe7b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java
@@ -92,9 +92,11 @@ public abstract class Repeat extends RBuiltinNode {
     protected void createCasts(CastBuilder casts) {
         Function<Object, Object> argType = this::argType;
         casts.arg("x").mustBe(abstractVectorValue(), RError.Message.ATTEMPT_TO_REPLICATE, argType);
-        casts.arg("times").defaultError(RError.Message.INVALID_ARGUMENT, "times").mustBe(nullValue().not()).asIntegerVector();
-        casts.arg("length.out").asIntegerVector().shouldBe(size(1), RError.Message.FIRST_ELEMENT_USED, "length.out").findFirst(1);
-        casts.arg("each").asIntegerVector().shouldBe(size(1), RError.Message.FIRST_ELEMENT_USED, "each").findFirst(1);
+        casts.arg("times").defaultError(RError.Message.INVALID_ARGUMENT, "times").asIntegerVector();
+        casts.arg("length.out").asIntegerVector().shouldBe(size(1).or(size(0)), RError.Message.FIRST_ELEMENT_USED, "length.out").findFirst(RRuntime.INT_NA,
+                        RError.Message.FIRST_ELEMENT_USED, "length.out").mustBe(intNA().or(gte(0)));
+        casts.arg("each").asIntegerVector().shouldBe(size(1).or(size(0)), RError.Message.FIRST_ELEMENT_USED, "each").findFirst(1, RError.Message.FIRST_ELEMENT_USED, "each").notNA(
+                        1).mustBe(gte(0));
     }
 
     protected boolean hasNames(RAbstractVector x) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java
index 7f06094b149caf725d448d3d353e6247432bd069..5e6dd9e0c0312c66a0d24fbafe8fdc8d8b8f78ae 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java
@@ -65,8 +65,8 @@ public abstract class RepeatInternal extends RBuiltinNode {
     protected void createCasts(CastBuilder casts) {
         Function<Object, Object> argType = this::argType;
         casts.arg("x").mustBe(abstractVectorValue(), RError.SHOW_CALLER2, RError.Message.ATTEMPT_TO_REPLICATE, argType);
-        casts.arg("times").mustBe(abstractVectorValue(), RError.SHOW_CALLER, RError.Message.INCORRECT_ARG_TYPE, "second").asIntegerVector().mustBe(notEmpty(), RError.SHOW_CALLER,
-                        RError.Message.INVALID_VALUE, "times");
+        casts.arg("times").defaultError(RError.SHOW_CALLER, RError.Message.INCORRECT_ARG_TYPE, "second").mustBe(abstractVectorValue()).asIntegerVector().mustBe(notEmpty(),
+                        RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "times");
     }
 
     @FunctionalInterface
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java
index da513b499b6d546ca31f20a88fb41a639f317134..f3a3b5fd67d73796c561e04398f1ddf36e12728b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java
@@ -44,8 +44,7 @@ public abstract class RepeatLength extends RBuiltinNode {
     protected void createCasts(CastBuilder casts) {
         casts.arg("x").mustBe(abstractVectorValue(), RError.SHOW_CALLER, RError.Message.ATTEMPT_TO_REPLICATE_NO_VECTOR);
         // with default error message, SHOW_CALLER does not work
-        casts.arg("length.out").asIntegerVector().mustBe(size(1), RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "length.out").findFirst(1).mustBe(notIntNA(), RError.SHOW_CALLER,
-                        RError.Message.INVALID_VALUE, "length.out");
+        casts.arg("length.out").defaultError(RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "length.out").asIntegerVector().mustBe(size(1)).findFirst().mustBe(notIntNA());
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rm.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rm.java
index 424332d735ac91a2cf4f20a1094af721f162d1f8..74eb30e05f18afe578d50382ab41fa390c7b1e91 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rm.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rm.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
@@ -63,7 +62,7 @@ public abstract class Rm extends RBuiltinNode {
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg("list").mustBe(stringValue(), SHOW_CALLER, INVALID_FIRST_ARGUMENT);
-        casts.arg("envir").mustBe(nullValue().not(), SHOW_CALLER, USE_NULL_ENV_DEFUNCT).mustBe(REnvironment.class, SHOW_CALLER, INVALID_ARGUMENT, "envir");
+        casts.arg("envir").mustNotBeNull(SHOW_CALLER, USE_NULL_ENV_DEFUNCT).mustBe(REnvironment.class, SHOW_CALLER, INVALID_ARGUMENT, "envir");
         casts.arg("inherits").mustBe(numericValue(), SHOW_CALLER, INVALID_ARGUMENT, "inherits").asLogicalVector().findFirst().map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Row.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Row.java
index a2504949798a07cff7305cb4cf8bad029b9f7329..a24d5c11c2b0f209ac0ac614e69a5dd7f6f9a3ee 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Row.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Row.java
@@ -13,7 +13,6 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size;
 import static com.oracle.truffle.r.runtime.RError.SHOW_CALLER;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
@@ -33,7 +32,7 @@ public abstract class Row extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("dims").mustBe(nullValue().not().and(integerValue()), SHOW_CALLER, RError.Message.MATRIX_LIKE_REQUIRED, "row").asIntegerVector().mustBe(size(2));
+        casts.arg("dims").defaultError(SHOW_CALLER, RError.Message.MATRIX_LIKE_REQUIRED, "row").mustBe(integerValue()).asIntegerVector().mustBe(size(2));
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java
index 70f24818979646f4ac10c6abfc5a9ec3b868fa98..1545fad43fdc0d6a5cc8735427e22703ffc06428 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java
@@ -18,7 +18,6 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.length;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lengthLte;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lt;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
@@ -109,12 +108,12 @@ public abstract class Scan extends RBuiltinNode {
 
         casts.arg("nmax").asIntegerVector().findFirst(0).notNA(0).mapIf(lt(0), constant(0));
 
-        casts.arg("sep").mustBe(nullValue().or(stringValue())).asStringVector().findFirst("").mustBe(lengthLte(1), RError.Message.MUST_BE_ONE_BYTE, "'sep' value");
+        casts.arg("sep").allowNull().mustBe(stringValue()).asStringVector().findFirst("").mustBe(lengthLte(1), RError.Message.MUST_BE_ONE_BYTE, "'sep' value");
 
-        casts.arg("dec").defaultError(RError.Message.INVALID_DECIMAL_SEP).mustBe(nullValue().or(stringValue())).asStringVector().findFirst(".").mustBe(length(1), RError.Message.MUST_BE_ONE_BYTE,
-                        "'sep' value");
+        casts.arg("dec").allowNull().defaultError(RError.Message.INVALID_DECIMAL_SEP).mustBe(stringValue()).asStringVector().findFirst(".").mustBe(length(1),
+                        RError.Message.MUST_BE_ONE_BYTE, "'sep' value");
 
-        casts.arg("quote").defaultError(RError.Message.INVALID_QUOTE_SYMBOL).mapIf(nullValue(), constant("")).mustBe(stringValue()).asStringVector().findFirst("");
+        casts.arg("quote").defaultError(RError.Message.INVALID_QUOTE_SYMBOL).mapNull(constant("")).mustBe(stringValue()).asStringVector().findFirst("");
 
         casts.arg("skip").asIntegerVector().findFirst(0).notNA(0).mapIf(lt(0), constant(0));
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqLen.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqLen.java
index 5ec3b669c501f8945145327a10f9f140b364ad07..bdc0b6c2cb31ad26f9f10551fa301d789410b3fb 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqLen.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqLen.java
@@ -44,8 +44,8 @@ public abstract class SeqLen extends RBuiltinNode {
         // seq_len(c("7", "b"))
         // GNU R (presumably) gets the first element before doing a coercion but I don't think we
         // can do it with our API
-        casts.arg("length.out").asIntegerVector().shouldBe(size(1), RError.Message.FIRST_ELEMENT_USED, "length.out").findFirst(RRuntime.INT_NA).mustBe(gte(0),
-                        RError.Message.MUST_BE_COERCIBLE_INTEGER);
+        casts.arg("length.out").asIntegerVector().shouldBe(size(1).or(size(0)), RError.Message.FIRST_ELEMENT_USED, "length.out").findFirst(RRuntime.INT_NA,
+                        RError.Message.FIRST_ELEMENT_USED, "length.out").mustBe(gte(0), RError.Message.MUST_BE_COERCIBLE_INTEGER);
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SerializeFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SerializeFunctions.java
index 438c5855bb4d37494b43dd47f8250e13e9385094..c82ccf48af8b739cac5ab953c713476211f24c9d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SerializeFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SerializeFunctions.java
@@ -112,7 +112,7 @@ public class SerializeFunctions {
         protected void createCasts(CastBuilder casts) {
             connection(casts);
             casts.arg("ascii").mustBe(logicalValue(), RError.Message.ASCII_NOT_LOGICAL);
-            casts.arg("version").mustBe(nullValue().or(integerValue()));
+            casts.arg("version").allowNull().mustBe(integerValue());
         }
 
         @Specialization
@@ -151,7 +151,7 @@ public class SerializeFunctions {
     public abstract static class Serialize extends Adapter {
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("con").mustBe(nullValue().or(instanceOf(RConnection.class)));
+            casts.arg("con").allowNull().mustBe(instanceOf(RConnection.class));
             casts.arg("type").asIntegerVector().findFirst();
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetS4Object.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetS4Object.java
index 4371caeddfe9632d03e9da6cf3d3406bfa7f6d76..766d4fa8206990008ebce258aa6f296b0f8d9714 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetS4Object.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetS4Object.java
@@ -46,7 +46,7 @@ public abstract class SetS4Object extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("object").asAttributable(true, true, true);
+        casts.arg("object").allowNull().asAttributable(true, true, true);
         casts.arg("flag").asLogicalVector().mustBe(singleElement(), RError.SHOW_CALLER, RError.Message.INVALID_ARGUMENT, "flag").findFirst().map(toBoolean());
         // "complete" can be a vector, unlike "flag"
         casts.arg("complete").asIntegerVector().findFirst(RError.SHOW_CALLER, RError.Message.INVALID_ARGUMENT, "complete");
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Signif.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Signif.java
index f0afe89b9da9ef449d92a95680338122f30940a6..f0c4adad1e2064a240d084694bc7f44d70360231 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Signif.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Signif.java
@@ -68,11 +68,12 @@ public abstract class Signif extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mustBe(numericValue().or(complexValue()), RError.Message.NON_NUMERIC_MATH).mapIf(complexValue().not(), asDoubleVector(true, true, true));
+        casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(numericValue().or(complexValue())).mapIf(complexValue().not(),
+                        asDoubleVector(true, true, true));
         // TODO: for the error messages to be consistent with GNU R we should chack for notEmpty()
         // first but it does not seem to be possible currently as numericValue() cannot be used on
         // the result of asVector()
-        casts.arg("digits").mustBe(numericValue(), RError.Message.NON_NUMERIC_MATH).asIntegerVector().mustBe(notEmpty(), RError.Message.INVALID_ARG_OF_LENGTH, "second", 0);
+        casts.arg("digits").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(numericValue()).asIntegerVector().mustBe(notEmpty(), RError.Message.INVALID_ARG_OF_LENGTH, "second", 0);
     }
 
     // TODO: consider porting signif implementation from GNU R
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Slot.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Slot.java
index 57dc5a43393f2e5352f159744dc7454830252ee1..2825463c7679da160107b42929f18bba1d333d5e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Slot.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Slot.java
@@ -39,7 +39,7 @@ public abstract class Slot extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg(0).asAttributable(true, true, true);
+        casts.arg(0).allowNull().asAttributable(true, true, true);
     }
 
     private String getName(Object nameObj) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
index 48572c7a8c378fda8f7eefac49e9ef77660dab36..94785a8690478872434d746b5b700a803c199412 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
@@ -92,7 +92,7 @@ public abstract class StandardGeneric extends RBuiltinNode {
         casts.arg("f").defaultError(RError.Message.GENERIC, "argument to 'standardGeneric' must be a non-empty character string").mustBe(
                         stringValue()).asStringVector().findFirst().mustBe(lengthGt(0));
         Function<Object, Object> argClass = this::argClass;
-        casts.arg("fdef").asAttributable(true, true, true).mustBe(missingValue().or(instanceOf(RFunction.class)), RError.SHOW_CALLER, RError.Message.EXPECTED_GENERIC, argClass);
+        casts.arg("fdef").defaultError(RError.SHOW_CALLER, RError.Message.EXPECTED_GENERIC, argClass).allowMissing().asAttributable(true, true, true).mustBe(instanceOf(RFunction.class));
     }
 
     private Object stdGenericInternal(VirtualFrame frame, String fname, RFunction fdef) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Stop.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Stop.java
index 2cdff7e1f4d1ae7422ac646a0563ef68d7c760b2..5e3b02e1532968c43043d37df862f19c73f67d5d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Stop.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Stop.java
@@ -39,7 +39,7 @@ public abstract class Stop extends RBuiltinNode {
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg("call").asLogicalVector().findFirst().map(toBoolean());
-        casts.arg("message").mustBe(stringValue().or(nullValue())).asStringVector().mustBe(notEmpty(), RError.Message.INVALID_STRING_IN_STOP).findFirst();
+        casts.arg("message").allowNull().mustBe(stringValue()).asStringVector().mustBe(notEmpty(), RError.Message.INVALID_STRING_IN_STOP).findFirst();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtrim.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtrim.java
index 6124f541a90c1eeefcf644560379ea0a185ed8ba..f5a41c88783a78f6aecb812890b104185daf94b2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtrim.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtrim.java
@@ -39,7 +39,7 @@ public abstract class Strtrim extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mustBe(Predef.stringValue(), Message.REQUIRES_CHAR_VECTOR, "strtrim()").asStringVector(true, true, true);
+        casts.arg("x").defaultError(Message.REQUIRES_CHAR_VECTOR, "strtrim()").mustBe(Predef.stringValue()).asStringVector(true, true, true);
         casts.arg("width").asIntegerVector();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Tabulate.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Tabulate.java
index 17cff1e7387cae9887f94e163a1a9151ca31831a..9accf74b28f744b5102b80960a6d1a4a85231668 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Tabulate.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Tabulate.java
@@ -32,7 +32,7 @@ public abstract class Tabulate extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("bin").mustBe(integerValue(), RError.NO_CALLER, RError.Message.INVALID_INPUT).asIntegerVector();
+        casts.arg("bin").defaultError(RError.NO_CALLER, RError.Message.INVALID_INPUT).mustBe(integerValue()).asIntegerVector();
         casts.arg("nbins").defaultError(RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "nbin").asIntegerVector().findFirst().mustBe(gte(0));
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java
index 3d86ab3e90c3fa99372e58729130d0555f52e82c..91a37a02172cbf7909d26be160a1eeaf6cf05651 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java
@@ -22,8 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.RVisibility.CUSTOM;
 import static com.oracle.truffle.r.runtime.RVisibility.OFF;
@@ -211,7 +209,7 @@ public class TraceFunctions {
     public abstract static class Tracemem extends TracememBase {
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").mustBe(nullValue().not(), Message.TRACEMEM_NOT_NULL);
+            casts.arg("x").mustNotBeNull(Message.TRACEMEM_NOT_NULL);
         }
 
         @Specialization
@@ -233,7 +231,7 @@ public class TraceFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("previous").defaultError(Message.INVALID_ARGUMENT, "previous").mustBe(stringValue().or(missingValue()));
+            casts.arg("previous").defaultError(Message.INVALID_ARGUMENT, "previous").allowNullAndMissing().mustBe(stringValue());
         }
 
         @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java
index 9f6d574f555cf4b776024d331357cadc9a50c460..de951eb0189f66ab35711e13616117cc9a7322b7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java
@@ -36,7 +36,7 @@ public abstract class UnClass extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").asAttributable(true, true, true);
+        casts.arg("x").allowNull().asAttributable(true, true, true);
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unique.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unique.java
index ea894dcbba0de2e02e1f80fcdb310dda99c097ea..4fdb50c52dff15e3a70fdb7bba2f5491d3d4ba30 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unique.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unique.java
@@ -71,13 +71,12 @@ public abstract class Unique extends RBuiltinNode {
     @Override
     protected void createCasts(CastBuilder casts) {
         // these are similar to those in DuplicatedFunctions.java
-        casts.arg("x").mustBe(nullValue().or(abstractVectorValue()), RError.SHOW_CALLER, RError.Message.APPLIES_TO_VECTORS,
-                        "unique()").mapIf(nullValue().not(), asVector());
+        casts.arg("x").defaultError(RError.SHOW_CALLER, RError.Message.APPLIES_TO_VECTORS, "unique()").allowNull().mustBe(abstractVectorValue()).asVector();
         // not much more can be done for incomparables as it is either a vector of incomparable
         // values or a (single) logical value
         // TODO: coercion error must be handled by specialization as it depends on type of x (much
         // like in duplicated)
-        casts.arg("incomparables").asVector(true);
+        casts.arg("incomparables").mapNull(emptyList()).asVector(true);
         casts.arg("fromLast").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
         // currently not supported and not tested, but NA is a correct value (the same for empty
         // vectors) whereas 0 is not (throws an error)
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 f27617a2fd13d84181bd9e7bc97fdb0ffcea59de..58111e5d065539993b265f95c4c63d6cf97e0313 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
@@ -30,6 +30,7 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.builtin.ArgumentFilter;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.Lapply.LapplyInternalNode;
@@ -93,7 +94,10 @@ public abstract class VApply extends RBuiltinNode {
     protected void createCasts(CastBuilder casts) {
         casts.arg("X").asVector();
         casts.arg("FUN").mustBe(instanceOf(RFunction.class), RError.SHOW_CALLER, RError.Message.APPLY_NON_FUNCTION);
-        casts.arg("FUN.VALUE").mapIf(anyValue(), chain(asVector(true)).with(mustBe(abstractVectorValue(), RError.SHOW_CALLER, true, RError.Message.MUST_BE_VECTOR, "FUN.VALUE")).end());
+        // casts.arg("FUN.VALUE").mapIf(anyValue(),
+        // chain(asVector(true)).with(mustBe(abstractVectorValue(), RError.SHOW_CALLER, true,
+        // RError.Message.MUST_BE_VECTOR, "FUN.VALUE")).end());
+        casts.arg("FUN.VALUE").defaultError(RError.SHOW_CALLER, RError.Message.MUST_BE_VECTOR, "FUN.VALUE").asVector(true).mustBe(abstractVectorValue());
         casts.arg("USE.NAMES").defaultError(RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "USE.NAMES").mustBe(stringValue().not()).asLogicalVector().findFirst();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java
index 17662ce966d830026fbd35be2cfbb5ba69a8f6b2..d2a68f643447bcf781b73b4345a3a81aaf195163 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java
@@ -135,7 +135,7 @@ public class WhichFunctions {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg(0, "x").asDoubleVector(true, false, false);
+            casts.arg(0, "x").allowNull().asDoubleVector(true, false, false);
         }
 
         @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java
index 8146e8d738e69121fe5a4f05d33c88a5bd2534ab..128ab8aada21d7636c21db5296b3943962fca3b1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
@@ -51,7 +50,7 @@ public abstract class WithVisible extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mustBe(missingValue().not(), RError.Message.ARGUMENT_MISSING, "x");
+        casts.arg("x").mustNotBeMissing(RError.Message.ARGUMENT_MISSING, "x");
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
index e353a90b127ebfafbf2ebe88ddddc9442333e7c1..9e594840c47c3468b33e46739511be30975aac77 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
@@ -60,7 +60,7 @@ public class FastRContext {
 
     private static final class Casts {
         private static void exprs(CastBuilder casts) {
-            casts.arg("exprs").asStringVector().mustBe(nullValue().not().and(notEmpty()));
+            casts.arg("exprs").asStringVector().mustBe(notEmpty());
         }
 
         private static void kind(CastBuilder casts) {
@@ -73,11 +73,11 @@ public class FastRContext {
         }
 
         private static void key(CastBuilder casts) {
-            casts.arg("key").asIntegerVector().mustBe(nullValue().not().and(notEmpty())).findFirst();
+            casts.arg("key").asIntegerVector().mustBe(notEmpty()).findFirst();
         }
 
         private static void id(CastBuilder casts) {
-            casts.arg("id").asIntegerVector().mustBe(nullValue().not().and(notEmpty())).findFirst();
+            casts.arg("id").asIntegerVector().mustBe(notEmpty()).findFirst();
         }
     }
 
@@ -133,7 +133,7 @@ public class FastRContext {
     public abstract static class Join extends RBuiltinNode {
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("handle").asIntegerVector().mustBe(nullValue().not().and(notEmpty()));
+            casts.arg("handle").asIntegerVector().mustBe(notEmpty());
         }
 
         @Specialization
@@ -226,7 +226,7 @@ public class FastRContext {
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("args").mustBe(missingValue().or(stringValue()));
+            casts.arg("args").allowMissing().mustBe(stringValue());
             casts.arg("intern").asLogicalVector().findFirst().map(toBoolean());
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStats.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStats.java
index 00291fa3aea3f30bf05581d607713ac8248128e1..9a25f3ecb67d606a58474392f45ede641fbddc9d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStats.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStats.java
@@ -62,7 +62,7 @@ public class FastRStats {
 
     private static final class Casts {
         private static void filename(CastBuilder casts) {
-            casts.arg("filename").mustBe(stringValue().or(nullValue())).asStringVector();
+            casts.arg("filename").allowNull().mustBe(stringValue()).asStringVector();
         }
 
         private static void append(CastBuilder casts) {
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/CastBuilderTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/CastBuilderTest.java
index 59c53a3b2bf420f933def6b0e638d534cb6256ff..abe4a463453d4c61a6d195e4fb3f5df4a35a455e 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/CastBuilderTest.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/CastBuilderTest.java
@@ -22,9 +22,43 @@
  */
 package com.oracle.truffle.r.nodes.builtin;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asLogicalVector;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.chain;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.complexValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.constant;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.defaultValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.dimGt;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleNA;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleToInt;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.elementAt;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.equalTo;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.findFirst;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.isFractional;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lte;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.map;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.mustBe;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notEmpty;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notNA;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullConstant;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.scalarLogicalValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.scalarStringValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.shouldBe;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.squareMatrix;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.trueValue;
 import static com.oracle.truffle.r.nodes.casts.CastUtils.samples;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.util.function.Function;
 
@@ -54,7 +88,6 @@ import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RInteger;
 import com.oracle.truffle.r.runtime.data.RList;
@@ -350,7 +383,7 @@ public class CastBuilderTest {
     @Test
     public void testMatchArg() {
 
-        cb.arg(0, "foo").mustBe(nullValue().or(scalarStringValue().and(equalTo("a").or(equalTo("b").or(equalTo("c"))))), RError.Message.GENERIC, "Invalid option").mapIf(nullValue(), constant("a"));
+        cb.arg(0, "foo").mapNull(constant("a")).mustBe(scalarStringValue().and(equalTo("a").or(equalTo("b").or(equalTo("c")))), RError.Message.GENERIC, "Invalid option");
 
         cb.arg(0, "foo").alias(pb -> matchStringArg(pb, "a", "b", "c")).mapIf(equalTo("c"), constant("sss"));
 
@@ -464,6 +497,7 @@ public class CastBuilderTest {
     }
 
     @Test
+    @SuppressWarnings("deprecation")
     public void testSample6() {
         cb.arg(0).map(defaultValue(RDataFactory.createStringVector(0))).mustBe(stringValue(), RError.Message.INVALID_ARGUMENT, "labels").asStringVector();
         testPipeline();
@@ -571,7 +605,7 @@ public class CastBuilderTest {
 
     @Test
     public void testSample13() {
-        cb.arg(0, "arg").mapIf(numericValue(), BoxPrimitiveNodeGen.create());
+        cb.arg(0, "arg").mapIf(numericValue(), () -> BoxPrimitiveNodeGen.create());
 
         Object res = cast(1);
         Assert.assertTrue(res instanceof RInteger);
@@ -582,7 +616,7 @@ public class CastBuilderTest {
 
     @Test
     public void testSample14() {
-        cb.arg(0, "arg").mustBe(stringValue().or(nullValue())).mapIf(stringValue(), chain(asStringVector()).with(findFirst().stringElement()).end());
+        cb.arg(0, "arg").allowNull().mustBe(stringValue()).asStringVector().findFirst();
 
         assertEquals("abc", cast("abc"));
         assertEquals("abc", cast(RDataFactory.createStringVector(new String[]{"abc", "xyz"}, true)));
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/TypeExprTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/TypeExprTest.java
index 02278b9ec81b0b2ce66cb16288b9b9bc35193881..c417e4e73e0165eab37e86ab64a1c90d9045e2bf 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/TypeExprTest.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/TypeExprTest.java
@@ -34,7 +34,10 @@ import java.util.Set;
 import org.junit.Assert;
 import org.junit.Test;
 
+import com.oracle.truffle.r.nodes.casts.CastUtils;
+import com.oracle.truffle.r.nodes.casts.Not;
 import com.oracle.truffle.r.nodes.casts.TypeConjunction;
+import com.oracle.truffle.r.nodes.casts.TypeExpr;
 import com.oracle.truffle.r.runtime.data.RIntSequence;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RSequence;
@@ -55,6 +58,22 @@ public class TypeExprTest {
         Assert.assertEquals(toSet(TypeConjunction.create(RAbstractIntVector.class, RAbstractStringVector.class)), atom(RAbstractIntVector.class).and(atom(RAbstractStringVector.class)).normalize());
     }
 
+    @Test
+    public void testContains() {
+        TypeExpr te = atom(String.class).or(atom(RNull.class).not());
+        Assert.assertTrue(te.contains(String.class));
+        Assert.assertTrue(te.contains(Not.negateType(RNull.class)));
+        Assert.assertFalse(te.contains(RNull.class));
+    }
+
+    @Test
+    public void testNot() {
+        TypeExpr from = atom(String.class).or(atom(RNull.class).not());
+        Assert.assertFalse(CastUtils.Casts.existsConvertibleActualType(from, RNull.class, false));
+        Assert.assertTrue(CastUtils.Casts.existsConvertibleActualType(from, String.class, false));
+        Assert.assertTrue(CastUtils.Casts.existsConvertibleActualType(from, Integer.class, false));
+    }
+
     private static Set<Type> toSet(Type... classes) {
         return new HashSet<>(Arrays.asList(classes));
     }
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/PredefFiltersSamplers.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/PredefFiltersSamplers.java
index e3d06ca662a06911ca24fa86fa0ed28ca90e5c0d..4f7556ccb6bb30ca1ad7120f42b9937a177c33ee 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/PredefFiltersSamplers.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/PredefFiltersSamplers.java
@@ -57,14 +57,6 @@ public final class PredefFiltersSamplers implements PredefFilters {
         return ValuePredicateArgumentFilterSampler.fromLambdaWithSamples(arg -> Objects.equals(arg, x), samples(x), CastUtils.<T> samples());
     }
 
-    @Override
-    public <T, R extends T> TypePredicateArgumentFilterSampler<T, R> nullValue() {
-        // return TypePredicateArgumentFilterSampler.fromLambda(x -> x == RNull.instance || x ==
-        // null, CastUtils.<R> samples(null), CastUtils.<R> samples(), RNull.class);
-        return new TypePredicateArgumentFilterSampler<>("nullValue()", x -> x == RNull.instance || x == null, CastUtils.<R> samples(null), CastUtils.<R> samples(), Collections.singleton(RNull.class),
-                        true);
-    }
-
     @Override
     public <T extends RAbstractVector> VectorPredicateArgumentFilterSampler<T> notEmpty() {
         return new VectorPredicateArgumentFilterSampler<>("notEmpty()", x -> x.getLength() > 0, false, 0);
@@ -324,11 +316,6 @@ public final class PredefFiltersSamplers implements PredefFilters {
         return TypePredicateArgumentFilterSampler.fromLambda(x -> x instanceof RComplex, RComplex.class);
     }
 
-    @Override
-    public TypePredicateArgumentFilterSampler<Object, RMissing> missingValue() {
-        return TypePredicateArgumentFilterSampler.fromLambda(x -> RMissing.instance == x, RMissing.class);
-    }
-
     private static String sampleString(int len) {
         if (len <= 0) {
             return "";
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/PredefMappersSamplers.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/PredefMappersSamplers.java
index 7f52b7c1b07f2cf5222d484de6b8d61c19559cb9..fea6278350ac58d0f45f0752c8b6fc76ede05ec8 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/PredefMappersSamplers.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/PredefMappersSamplers.java
@@ -27,9 +27,18 @@ import static com.oracle.truffle.r.nodes.casts.CastUtils.samples;
 import java.util.Collections;
 
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.builtin.ValuePredicateArgumentMapper;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.PredefMappers;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RComplexVector;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.RIntVector;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RLogicalVector;
+import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public final class PredefMappersSamplers implements PredefMappers {
@@ -75,6 +84,11 @@ public final class PredefMappersSamplers implements PredefMappers {
         return ValuePredicateArgumentMapperSampler.fromLambda((T x) -> RNull.instance, null, null, RNull.class);
     }
 
+    @Override
+    public <T> ValuePredicateArgumentMapperSampler<T, RMissing> missingConstant() {
+        return ValuePredicateArgumentMapperSampler.fromLambda((T x) -> RMissing.instance, null, null, RMissing.class);
+    }
+
     @Override
     public <T> ValuePredicateArgumentMapperSampler<T, String> constant(String s) {
         return ValuePredicateArgumentMapperSampler.fromLambda((T x) -> s, (String x) -> null, CastUtils.<T> samples(), CastUtils.<T> samples(), null,
@@ -98,6 +112,37 @@ public final class PredefMappersSamplers implements PredefMappers {
     }
 
     @Override
+    public <T> ValuePredicateArgumentMapperSampler<T, RIntVector> emptyIntegerVector() {
+        return ValuePredicateArgumentMapperSampler.fromLambda(x -> RDataFactory.createEmptyIntVector(), x -> null, CastUtils.<T> samples(), CastUtils.<T> samples(), null, RIntVector.class);
+    }
+
+    @Override
+    public <T> ValuePredicateArgumentMapper<T, RDoubleVector> emptyDoubleVector() {
+        return ValuePredicateArgumentMapperSampler.fromLambda(x -> RDataFactory.createEmptyDoubleVector(), x -> null, CastUtils.<T> samples(), CastUtils.<T> samples(), null, RDoubleVector.class);
+    }
+
+    @Override
+    public <T> ValuePredicateArgumentMapper<T, RLogicalVector> emptyLogicalVector() {
+        return ValuePredicateArgumentMapperSampler.fromLambda(x -> RDataFactory.createEmptyLogicalVector(), x -> null, CastUtils.<T> samples(), CastUtils.<T> samples(), null, RLogicalVector.class);
+    }
+
+    @Override
+    public <T> ValuePredicateArgumentMapper<T, RComplexVector> emptyComplexVector() {
+        return ValuePredicateArgumentMapperSampler.fromLambda(x -> RDataFactory.createEmptyComplexVector(), x -> null, CastUtils.<T> samples(), CastUtils.<T> samples(), null, RComplexVector.class);
+    }
+
+    @Override
+    public <T> ValuePredicateArgumentMapper<T, RStringVector> emptyStringVector() {
+        return ValuePredicateArgumentMapperSampler.fromLambda(x -> RDataFactory.createEmptyStringVector(), x -> null, CastUtils.<T> samples(), CastUtils.<T> samples(), null, RStringVector.class);
+    }
+
+    @Override
+    public <T> ValuePredicateArgumentMapper<T, RList> emptyList() {
+        return ValuePredicateArgumentMapperSampler.fromLambda(x -> RDataFactory.createList(), x -> null, CastUtils.<T> samples(), CastUtils.<T> samples(), null, RList.class);
+    }
+
+    @Override
+    @Deprecated
     public <T> ArgumentMapperSampler<T, T> defaultValue(T defVal) {
 
         assert (defVal != null);
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/Samples.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/Samples.java
index e548800b848bc5c046f89e56cf59a3a0dd042cbf..2819f8e63942c3ae3b111b5a55d1f5e4d5116f21 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/Samples.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/Samples.java
@@ -33,6 +33,7 @@ import java.util.stream.Collectors;
 public final class Samples<T> {
 
     private static final Samples<?> ANYTHING = new Samples<>("anything", Collections.emptySet(), Collections.emptySet(), x -> true);
+    private static final Samples<?> NOTHING = new Samples<>("nothing", Collections.emptySet(), Collections.emptySet(), x -> false);
 
     @SuppressWarnings("unchecked")
     public static <T> Samples<T> anything() {
@@ -43,6 +44,11 @@ public final class Samples<T> {
         return new Samples<>("anything(" + x + ")", Collections.singleton(x), Collections.emptySet(), xx -> true);
     }
 
+    @SuppressWarnings("unchecked")
+    public static <T> Samples<T> nothing() {
+        return (Samples<T>) NOTHING;
+    }
+
     private final Set<? extends T> posSamples;
     private final Set<?> negSamples;
     private final Predicate<Object> posMembership;
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/TestCasts.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/TestCasts.java
index 1a8c6e4272263f78eab2371f775570e1d57d4fb4..27d7ca784adf3cb42ed4e30ce1e11a401607a597 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/TestCasts.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/TestCasts.java
@@ -38,7 +38,6 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lengthLte;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lt;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.scalarIntegerValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.scalarLogicalValue;
@@ -199,6 +198,7 @@ public class TestCasts extends TestBase {
     public void testMapDefaultValue() {
         class Root extends TestRootNode<CastNode> {
 
+            @SuppressWarnings("deprecation")
             protected Root(String name) {
                 super(name, new CastBuilder().arg(0).map(defaultValue("X")).builder().getCasts()[0]);
             }
@@ -346,7 +346,7 @@ public class TestCasts extends TestBase {
 
             @SuppressWarnings("deprecation")
             protected Root(String name) {
-                super(name, new CastBuilder().arg(0).mustBe(numericValue()).asVector().mustBe(singleElement()).findFirst().mustBe(nullValue().not()).shouldBe(
+                super(name, new CastBuilder().arg(0).mustBe(numericValue()).asVector().mustBe(singleElement()).findFirst().shouldBe(
                                 ValuePredicateArgumentFilterSampler.fromLambdaWithResTypes(x -> x instanceof Byte || x instanceof Integer && ((Integer) x) > 0, Object.class),
                                 Message.NON_POSITIVE_FILL).mapIf(scalarLogicalValue(), asBoolean(), asInteger()).builder().getCasts()[0]);
             }
@@ -446,7 +446,7 @@ public class TestCasts extends TestBase {
 
             @SuppressWarnings("deprecation")
             protected Root(String name) {
-                super(name, new CastBuilder().arg(0).mustBe(numericValue()).asVector().mustBe(singleElement()).findFirst().mustBe(nullValue().not()).shouldBe(
+                super(name, new CastBuilder().arg(0).mustBe(numericValue()).asVector().mustBe(singleElement()).findFirst().shouldBe(
                                 instanceOf(Byte.class).or(instanceOf(Integer.class).and(gt0())), Message.NON_POSITIVE_FILL).mapIf(scalarLogicalValue(), asBoolean(),
                                                 asInteger()).builder().getCasts()[0]);
             }
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/TypeExpr.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/TypeExpr.java
index 32ae7bcc5e976b28d118869730659d86db62a44a..a462d9311b4c998c8eb7295c7a2c7b486a12bab8 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/TypeExpr.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/TypeExpr.java
@@ -74,6 +74,10 @@ public final class TypeExpr {
         return new TypeExpr(newDisjNormForm);
     }
 
+    public boolean contains(Type tp) {
+        return disjNormForm.stream().flatMap(conjSet -> conjSet.stream().filter(t -> t.equals(tp))).findFirst().isPresent();
+    }
+
     public TypeExpr or(TypeExpr te) {
         Set<Set<? extends Type>> newDisjNormForm = new HashSet<>(this.disjNormForm);
         newDisjNormForm.addAll(te.disjNormForm);
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/BypassNodeGenSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/BypassNodeGenSampler.java
new file mode 100644
index 0000000000000000000000000000000000000000..32540f59b3e7d34604b2bb8d25f66085726b98cc
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/BypassNodeGenSampler.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016, 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.unary;
+
+import com.oracle.truffle.r.nodes.casts.ArgumentMapperSampler;
+import com.oracle.truffle.r.nodes.casts.CastNodeSampler;
+import com.oracle.truffle.r.nodes.casts.Samples;
+import com.oracle.truffle.r.nodes.casts.TypeExpr;
+import com.oracle.truffle.r.runtime.data.RMissing;
+import com.oracle.truffle.r.runtime.data.RNull;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class BypassNodeGenSampler extends CastNodeSampler<BypassNodeGen> {
+
+    private final CastNodeSampler wrappedHeadSampler;
+    private final ArgumentMapperSampler nullMapper;
+    private final ArgumentMapperSampler missingMapper;
+
+    public BypassNodeGenSampler(BypassNodeGen bypassNode) {
+        super(bypassNode);
+        this.wrappedHeadSampler = bypassNode.getWrappedHead() == null ? null : createSampler(bypassNode.getWrappedHead());
+
+        assert bypassNode.getNullMapper() == null || bypassNode.getNullMapper() instanceof ArgumentMapperSampler;
+        assert bypassNode.getMissingMapper() == null || bypassNode.getMissingMapper() instanceof ArgumentMapperSampler;
+
+        this.nullMapper = (ArgumentMapperSampler) bypassNode.getNullMapper();
+        this.missingMapper = (ArgumentMapperSampler) bypassNode.getMissingMapper();
+    }
+
+    @Override
+    public TypeExpr resultTypes(TypeExpr inputTypes) {
+        TypeExpr rt = wrappedHeadSampler == null ? TypeExpr.ANYTHING : wrappedHeadSampler.resultTypes(inputTypes);
+        if (nullMapper != null) {
+            rt = rt.or(nullMapper.resultTypes(inputTypes));
+        } else {
+            rt = rt.and(TypeExpr.atom(RNull.class).not());
+        }
+        if (missingMapper != null) {
+            rt = rt.or(missingMapper.resultTypes(inputTypes));
+        } else {
+            rt = rt.and(TypeExpr.atom(RMissing.class).not());
+        }
+        return rt;
+    }
+
+    @Override
+    public Samples<?> collectSamples(TypeExpr inputType, Samples<?> downStreamSamples) {
+        Samples<?> samples = wrappedHeadSampler == null ? Samples.nothing() : wrappedHeadSampler.collectSamples(inputType, downStreamSamples);
+        if (nullMapper != null) {
+            samples = samples.or(nullMapper.collectSamples(downStreamSamples));
+        }
+        if (missingMapper != null) {
+            samples = samples.or(missingMapper.collectSamples(downStreamSamples));
+        }
+        return samples;
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FindFirstNodeGenSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FindFirstNodeGenSampler.java
index 0b92ad8b7dcc6f93b0e971727b1b71ea6bad8ebb..41c209dffdb66291a1e90a5e2d980801ad43e158 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FindFirstNodeGenSampler.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FindFirstNodeGenSampler.java
@@ -115,16 +115,19 @@ public class FindFirstNodeGenSampler extends CastNodeSampler<FindFirstNodeGen> {
 
     @Override
     public TypeExpr resultTypes(TypeExpr inputType) {
+        TypeExpr rt;
         if (elementClass == null || elementClass == Object.class) {
             if (inputType.isAnything()) {
-                return TypeExpr.atom(RAbstractVector.class).not();
+                rt = TypeExpr.atom(RAbstractVector.class).not();
             } else {
                 Set<Type> resTypes = inputType.classify().stream().map(c -> CastUtils.elementType(c)).collect(Collectors.toSet());
-                return TypeExpr.union(resTypes);
+                rt = TypeExpr.union(resTypes);
             }
         } else {
-            return TypeExpr.atom(elementClass);
+            rt = TypeExpr.atom(elementClass);
         }
+
+        return rt;
     }
 
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/ColonNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/ColonNode.java
index ea4d74871de8b70c70c87123b73c6542a66f4122..2088157c587c8dc90b5dd376acd667cd3481d252 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/ColonNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/ColonNode.java
@@ -57,7 +57,7 @@ public abstract class ColonNode extends RBuiltinNode {
     protected void createCasts(CastBuilder casts) {
         // These casts should not be custom, but they are very hard to get right in a generic way.
         // Also, the proper warnings cannot be produced at the moment.
-        casts.custom(0, ColonCastNodeGen.create()).custom(1, ColonCastNodeGen.create());
+        casts.custom(0, () -> ColonCastNodeGen.create()).custom(1, () -> ColonCastNodeGen.create());
     }
 
     private void naCheck(boolean na) {
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 af2d450b92379eb3373baf791b62aab0e71947c5..0f7c93ede71dcb0797ecf2dc6473f88d3ff1eb9b 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
@@ -31,6 +31,7 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNodeGen;
 import com.oracle.truffle.r.nodes.builtin.ArgumentFilter.ArgumentTypeFilter;
 import com.oracle.truffle.r.nodes.builtin.ArgumentFilter.ArgumentValueFilter;
+import com.oracle.truffle.r.nodes.unary.BypassNode;
 import com.oracle.truffle.r.nodes.unary.CastComplexNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastDoubleBaseNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNodeGen;
@@ -59,9 +60,16 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RComplex;
+import com.oracle.truffle.r.runtime.data.RComplexVector;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.RIntVector;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRaw;
+import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
@@ -75,11 +83,14 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public final class CastBuilder {
 
-    private static final CastNode[] EMPTY_CASTS_ARRAY = new CastNode[0];
+    private static final CastNodeFactory[] EMPTY_CAST_FACT_ARRAY = new CastNodeFactory[0];
+    private static final PipelineConfigBuilder[] EMPTY_PIPELINE_CFG_BUILDER_ARRAY = new PipelineConfigBuilder[0];
 
     private final RBuiltinNode builtinNode;
 
-    private CastNode[] casts = EMPTY_CASTS_ARRAY;
+    private CastNodeFactory[] castFactories = EMPTY_CAST_FACT_ARRAY;
+    private PipelineConfigBuilder[] pipelineCfgBuilders = EMPTY_PIPELINE_CFG_BUILDER_ARRAY;
+    private CastNode[] castsWrapped = null;
 
     public CastBuilder(RBuiltinNode builtinNode) {
         this.builtinNode = builtinNode;
@@ -89,32 +100,52 @@ public final class CastBuilder {
         this(null);
     }
 
-    private CastBuilder insert(int index, CastNode cast) {
-        if (index >= casts.length) {
-            casts = Arrays.copyOf(casts, index + 1);
+    @FunctionalInterface
+    public interface CastNodeFactory {
+        CastNode create();
+    }
+
+    private CastBuilder insert(int index, final CastNodeFactory castNodeFactory) {
+        if (index >= castFactories.length) {
+            castFactories = Arrays.copyOf(castFactories, index + 1);
         }
-        if (casts[index] == null) {
-            casts[index] = cast;
+        final CastNodeFactory cnf = castFactories[index];
+        if (cnf == null) {
+            castFactories[index] = castNodeFactory;
         } else {
-            casts[index] = new ChainedCastNode(casts[index], cast);
+            castFactories[index] = () -> new ChainedCastNode(cnf, castNodeFactory);
         }
         return this;
     }
 
     public CastNode[] getCasts() {
-        return casts;
+        if (castsWrapped == null) {
+            int len = Math.max(castFactories.length, pipelineCfgBuilders.length);
+            castsWrapped = new CastNode[len];
+            for (int i = 0; i < len; i++) {
+                CastNodeFactory cnf = i < castFactories.length ? castFactories[i] : null;
+                CastNode cn = cnf == null ? null : cnf.create();
+                if (i < pipelineCfgBuilders.length && pipelineCfgBuilders[i] != null) {
+                    castsWrapped[i] = BypassNode.create(pipelineCfgBuilders[i], cnf == null ? null : cn);
+                } else {
+                    castsWrapped[i] = cn;
+                }
+            }
+        }
+
+        return castsWrapped;
     }
 
     public CastBuilder toAttributable(int index, boolean preserveNames, boolean dimensionsPreservation, boolean attrPreservation) {
-        return insert(index, CastToAttributableNodeGen.create(preserveNames, dimensionsPreservation, attrPreservation));
+        return insert(index, () -> CastToAttributableNodeGen.create(preserveNames, dimensionsPreservation, attrPreservation));
     }
 
     public CastBuilder toVector(int index) {
-        return insert(index, CastToVectorNodeGen.create(false));
+        return insert(index, () -> CastToVectorNodeGen.create(false));
     }
 
     public CastBuilder toVector(int index, boolean preserveNonVector) {
-        return insert(index, CastToVectorNodeGen.create(preserveNonVector));
+        return insert(index, () -> CastToVectorNodeGen.create(preserveNonVector));
     }
 
     public CastBuilder toInteger(int index) {
@@ -122,7 +153,7 @@ public final class CastBuilder {
     }
 
     public CastBuilder toInteger(int index, boolean preserveNames, boolean dimensionsPreservation, boolean attrPreservation) {
-        return insert(index, CastIntegerNodeGen.create(preserveNames, dimensionsPreservation, attrPreservation));
+        return insert(index, () -> CastIntegerNodeGen.create(preserveNames, dimensionsPreservation, attrPreservation));
     }
 
     public CastBuilder toDouble(int index) {
@@ -130,57 +161,57 @@ public final class CastBuilder {
     }
 
     public CastBuilder toDouble(int index, boolean preserveNames, boolean dimensionsPreservation, boolean attrPreservation) {
-        return insert(index, CastDoubleNodeGen.create(preserveNames, dimensionsPreservation, attrPreservation));
+        return insert(index, () -> CastDoubleNodeGen.create(preserveNames, dimensionsPreservation, attrPreservation));
     }
 
     public CastBuilder toLogical(int index) {
-        return insert(index, CastLogicalNodeGen.create(false, false, false));
+        return insert(index, () -> CastLogicalNodeGen.create(false, false, false));
     }
 
     public CastBuilder toCharacter(int index) {
-        return insert(index, CastStringNodeGen.create(false, false, false));
+        return insert(index, () -> CastStringNodeGen.create(false, false, false));
     }
 
     public CastBuilder toCharacter(int index, boolean preserveNames, boolean dimensionsPreservation, boolean attrPreservation) {
-        return insert(index, CastStringNodeGen.create(preserveNames, dimensionsPreservation, attrPreservation));
+        return insert(index, () -> CastStringNodeGen.create(preserveNames, dimensionsPreservation, attrPreservation));
     }
 
     public CastBuilder toComplex(int index) {
-        return insert(index, CastComplexNodeGen.create(false, false, false));
+        return insert(index, () -> CastComplexNodeGen.create(false, false, false));
     }
 
     public CastBuilder toRaw(int index) {
-        return insert(index, CastRawNodeGen.create(false, false, false));
+        return insert(index, () -> CastRawNodeGen.create(false, false, false));
     }
 
     public CastBuilder boxPrimitive(int index) {
-        return insert(index, BoxPrimitiveNodeGen.create());
+        return insert(index, () -> BoxPrimitiveNodeGen.create());
     }
 
-    public CastBuilder custom(int index, CastNode cast) {
-        return insert(index, cast);
+    public CastBuilder custom(int index, CastNodeFactory castNodeFactory) {
+        return insert(index, castNodeFactory);
     }
 
     public CastBuilder firstIntegerWithWarning(int index, int intNa, String name) {
-        insert(index, CastIntegerNodeGen.create(false, false, false));
-        return insert(index, FirstIntNode.createWithWarning(RError.Message.FIRST_ELEMENT_USED, name, intNa));
+        insert(index, () -> CastIntegerNodeGen.create(false, false, false));
+        return insert(index, () -> FirstIntNode.createWithWarning(RError.Message.FIRST_ELEMENT_USED, name, intNa));
     }
 
     public CastBuilder firstIntegerWithError(int index, RError.Message error, String name) {
-        insert(index, CastIntegerNodeGen.create(false, false, false));
-        return insert(index, FirstIntNode.createWithError(error, name));
+        insert(index, () -> CastIntegerNodeGen.create(false, false, false));
+        return insert(index, () -> FirstIntNode.createWithError(error, name));
     }
 
     public CastBuilder firstStringWithError(int index, RError.Message error, String name) {
-        return insert(index, FirstStringNode.createWithError(error, name));
+        return insert(index, () -> FirstStringNode.createWithError(error, name));
     }
 
     public CastBuilder firstBoolean(int index) {
-        return insert(index, FirstBooleanNodeGen.create(null));
+        return insert(index, () -> FirstBooleanNodeGen.create(null));
     }
 
     public CastBuilder firstBoolean(int index, String invalidValueName) {
-        return insert(index, FirstBooleanNodeGen.create(invalidValueName));
+        return insert(index, () -> FirstBooleanNodeGen.create(invalidValueName));
     }
 
     public CastBuilder firstLogical(int index) {
@@ -188,15 +219,15 @@ public final class CastBuilder {
         return this;
     }
 
-    public InitialPhaseBuilder<Object> arg(int argumentIndex, String argumentName) {
-        return new ArgCastBuilderFactoryImpl(argumentIndex, argumentName).newInitialPhaseBuilder();
+    public PreinitialPhaseBuilder<Object> arg(int argumentIndex, String argumentName) {
+        return new ArgCastBuilderFactoryImpl(argumentIndex, argumentName).newPreinitialPhaseBuilder();
     }
 
-    public InitialPhaseBuilder<Object> arg(int argumentIndex) {
+    public PreinitialPhaseBuilder<Object> arg(int argumentIndex) {
         return arg(argumentIndex, builtinNode == null ? null : builtinNode.getRBuiltin().parameterNames()[argumentIndex]);
     }
 
-    public InitialPhaseBuilder<Object> arg(String argumentName) {
+    public PreinitialPhaseBuilder<Object> arg(String argumentName) {
         return arg(getArgumentIndex(argumentName), argumentName);
     }
 
@@ -234,8 +265,6 @@ public final class CastBuilder {
 
         <T> ValuePredicateArgumentFilter<T> equalTo(T x);
 
-        <T, R extends T> TypePredicateArgumentFilter<T, R> nullValue();
-
         <T extends RAbstractVector> VectorPredicateArgumentFilter<T> notEmpty();
 
         <T extends RAbstractVector> VectorPredicateArgumentFilter<T> singleElement();
@@ -330,8 +359,6 @@ public final class CastBuilder {
 
         TypePredicateArgumentFilter<Object, RComplex> scalarComplexValue();
 
-        TypePredicateArgumentFilter<Object, RMissing> missingValue();
-
     }
 
     public interface PredefMappers {
@@ -343,6 +370,8 @@ public final class CastBuilder {
 
         <T> ValuePredicateArgumentMapper<T, RNull> nullConstant();
 
+        <T> ValuePredicateArgumentMapper<T, RMissing> missingConstant();
+
         <T> ValuePredicateArgumentMapper<T, String> constant(String s);
 
         <T> ValuePredicateArgumentMapper<T, Integer> constant(int i);
@@ -351,6 +380,19 @@ public final class CastBuilder {
 
         <T> ValuePredicateArgumentMapper<T, Byte> constant(byte l);
 
+        <T> ValuePredicateArgumentMapper<T, RIntVector> emptyIntegerVector();
+
+        <T> ValuePredicateArgumentMapper<T, RDoubleVector> emptyDoubleVector();
+
+        <T> ValuePredicateArgumentMapper<T, RLogicalVector> emptyLogicalVector();
+
+        <T> ValuePredicateArgumentMapper<T, RComplexVector> emptyComplexVector();
+
+        <T> ValuePredicateArgumentMapper<T, RStringVector> emptyStringVector();
+
+        <T> ValuePredicateArgumentMapper<T, RList> emptyList();
+
+        @Deprecated
         <T> ArgumentMapper<T, T> defaultValue(T defVal);
 
     }
@@ -367,11 +409,6 @@ public final class CastBuilder {
             return ValuePredicateArgumentFilter.fromLambda(arg -> Objects.equals(arg, x));
         }
 
-        @Override
-        public <T, R extends T> TypePredicateArgumentFilter<T, R> nullValue() {
-            return new TypePredicateArgumentFilter<>(x -> x == RNull.instance, true);
-        }
-
         @Override
         public <T extends RAbstractVector> VectorPredicateArgumentFilter<T> notEmpty() {
             return new VectorPredicateArgumentFilter<>(x -> x.getLength() > 0, false);
@@ -628,11 +665,6 @@ public final class CastBuilder {
             return TypePredicateArgumentFilter.fromLambda(x -> x instanceof RComplex);
         }
 
-        @Override
-        public TypePredicateArgumentFilter<Object, RMissing> missingValue() {
-            return TypePredicateArgumentFilter.fromLambda(x -> RMissing.instance == x);
-        }
-
     }
 
     public static final class DefaultPredefMappers implements PredefMappers {
@@ -673,6 +705,11 @@ public final class CastBuilder {
             return ValuePredicateArgumentMapper.fromLambda(x -> RNull.instance);
         }
 
+        @Override
+        public <T> ValuePredicateArgumentMapper<T, RMissing> missingConstant() {
+            return ValuePredicateArgumentMapper.fromLambda(x -> RMissing.instance);
+        }
+
         @Override
         public <T> ValuePredicateArgumentMapper<T, String> constant(String s) {
             return ValuePredicateArgumentMapper.fromLambda((T x) -> s);
@@ -694,6 +731,37 @@ public final class CastBuilder {
         }
 
         @Override
+        public <T> ValuePredicateArgumentMapper<T, RIntVector> emptyIntegerVector() {
+            return ValuePredicateArgumentMapper.fromLambda(x -> RDataFactory.createEmptyIntVector());
+        }
+
+        @Override
+        public <T> ValuePredicateArgumentMapper<T, RDoubleVector> emptyDoubleVector() {
+            return ValuePredicateArgumentMapper.fromLambda(x -> RDataFactory.createEmptyDoubleVector());
+        }
+
+        @Override
+        public <T> ValuePredicateArgumentMapper<T, RLogicalVector> emptyLogicalVector() {
+            return ValuePredicateArgumentMapper.fromLambda(x -> RDataFactory.createEmptyLogicalVector());
+        }
+
+        @Override
+        public <T> ValuePredicateArgumentMapper<T, RComplexVector> emptyComplexVector() {
+            return ValuePredicateArgumentMapper.fromLambda(x -> RDataFactory.createEmptyComplexVector());
+        }
+
+        @Override
+        public <T> ValuePredicateArgumentMapper<T, RStringVector> emptyStringVector() {
+            return ValuePredicateArgumentMapper.fromLambda(x -> RDataFactory.createEmptyStringVector());
+        }
+
+        @Override
+        public <T> ValuePredicateArgumentMapper<T, RList> emptyList() {
+            return ValuePredicateArgumentMapper.fromLambda(x -> RDataFactory.createList());
+        }
+
+        @Override
+        @Deprecated
         public <T> ArgumentMapper<T, T> defaultValue(T defVal) {
 
             assert (defVal != null);
@@ -906,10 +974,6 @@ public final class CastBuilder {
             return predefFilters().equalTo(x);
         }
 
-        public static <T, R extends T> TypePredicateArgumentFilter<T, R> nullValue() {
-            return predefFilters().nullValue();
-        }
-
         public static <T extends RAbstractVector> VectorPredicateArgumentFilter<T> notEmpty() {
             return predefFilters().notEmpty();
         }
@@ -1138,16 +1202,20 @@ public final class CastBuilder {
             return predefFilters().anyValue();
         }
 
-        public static ArgumentTypeFilter<Object, Object> numericValue() {
-            return integerValue().or(doubleValue()).or(logicalValue());
+        @SuppressWarnings({"rawtypes", "unchecked", "cast"})
+        public static ArgumentTypeFilter<Object, RAbstractVector> numericValue() {
+            ArgumentTypeFilter f = integerValue().or(doubleValue()).or(logicalValue());
+            return (ArgumentTypeFilter<Object, RAbstractVector>) f;
         }
 
         /**
          * Checks that the argument is a list or vector/scalar of type numeric, string, complex or
          * raw.
          */
-        public static ArgumentTypeFilter<Object, Object> abstractVectorValue() {
-            return numericValue().or(stringValue()).or(complexValue()).or(rawValue()).or(instanceOf(RAbstractListVector.class));
+        @SuppressWarnings({"rawtypes", "unchecked", "cast"})
+        public static ArgumentTypeFilter<Object, RAbstractVector> abstractVectorValue() {
+            ArgumentTypeFilter f = numericValue().or(stringValue()).or(complexValue()).or(rawValue()).or(instanceOf(RAbstractListVector.class));
+            return (ArgumentTypeFilter<Object, RAbstractVector>) f;
         }
 
         /**
@@ -1190,10 +1258,6 @@ public final class CastBuilder {
             return predefFilters().scalarComplexValue();
         }
 
-        public static TypePredicateArgumentFilter<Object, RMissing> missingValue() {
-            return predefFilters().missingValue();
-        }
-
         public static ValuePredicateArgumentMapper<Byte, Boolean> toBoolean() {
             return predefMappers().toBoolean();
         }
@@ -1210,6 +1274,10 @@ public final class CastBuilder {
             return predefMappers().nullConstant();
         }
 
+        public static <T> ValuePredicateArgumentMapper<T, RMissing> missingConstant() {
+            return predefMappers().missingConstant();
+        }
+
         public static <T> ValuePredicateArgumentMapper<T, String> constant(String s) {
             return predefMappers().constant(s);
         }
@@ -1226,6 +1294,36 @@ public final class CastBuilder {
             return predefMappers().constant(l);
         }
 
+        public static <T> ValuePredicateArgumentMapper<T, RIntVector> emptyIntegerVector() {
+            return predefMappers.emptyIntegerVector();
+        }
+
+        public static <T> ValuePredicateArgumentMapper<T, RDoubleVector> emptyDoubleVector() {
+            return predefMappers.emptyDoubleVector();
+        }
+
+        public static <T> ValuePredicateArgumentMapper<T, RLogicalVector> emptyLogicalVector() {
+            return predefMappers.emptyLogicalVector();
+        }
+
+        public static <T> ValuePredicateArgumentMapper<T, RComplexVector> emptyComplexVector() {
+            return predefMappers.emptyComplexVector();
+        }
+
+        public static <T> ValuePredicateArgumentMapper<T, RStringVector> emptyStringVector() {
+            return predefMappers.emptyStringVector();
+        }
+
+        public static <T> ValuePredicateArgumentMapper<T, RList> emptyList() {
+            return predefMappers.emptyList();
+        }
+
+        /**
+         * @deprecated use the <code>mapNull</code> step, e.g.
+         *             <code>casts.arg("x").mapNull(emptyDoubleVector())</code> or
+         *             <code>casts.arg("x").conf(c -> c.mapNull(emptyDoubleVector()))</code> instead
+         */
+        @Deprecated
         public static <T> ArgumentMapper<T, T> defaultValue(T defVal) {
             return predefMappers().defaultValue(defVal);
         }
@@ -1262,12 +1360,12 @@ public final class CastBuilder {
         }
 
         default THIS shouldBe(ArgumentFilter<? super T, ?> argFilter, RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), FilterNode.create(argFilter, true, null, message, messageArgs, state().boxPrimitives));
+            state().castBuilder().insert(state().index(), () -> FilterNode.create(argFilter, true, null, message, messageArgs, state().boxPrimitives));
             return (THIS) this;
         }
 
         default THIS shouldBe(ArgumentFilter<? super T, ?> argFilter, RBaseNode callObj, RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), FilterNode.create(argFilter, true, callObj, message, messageArgs, state().boxPrimitives));
+            state().castBuilder().insert(state().index(), () -> FilterNode.create(argFilter, true, callObj, message, messageArgs, state().boxPrimitives));
             return (THIS) this;
         }
 
@@ -1283,7 +1381,7 @@ public final class CastBuilder {
 
     interface ArgCastBuilderFactory {
 
-        InitialPhaseBuilder<Object> newInitialPhaseBuilder();
+        PreinitialPhaseBuilder<Object> newPreinitialPhaseBuilder();
 
         <T> InitialPhaseBuilder<T> newInitialPhaseBuilder(ArgCastBuilder<?, ?> currentBuilder);
 
@@ -1293,10 +1391,10 @@ public final class CastBuilder {
 
     }
 
-    static class DefaultError {
-        final RBaseNode callObj;
-        final RError.Message message;
-        final Object[] args;
+    public static class DefaultError {
+        public final RBaseNode callObj;
+        public final RError.Message message;
+        public final Object[] args;
 
         DefaultError(RBaseNode callObj, RError.Message message, Object... args) {
             this.callObj = callObj;
@@ -1304,6 +1402,14 @@ public final class CastBuilder {
             this.args = args;
         }
 
+        public DefaultError fixCallObj(RBaseNode callObjFix) {
+            if (callObj == null) {
+                return new DefaultError(callObjFix, message, args);
+            } else {
+                return this;
+            }
+        }
+
     }
 
     static class ArgCastBuilderState {
@@ -1398,7 +1504,7 @@ public final class CastBuilder {
         }
 
         void mustBe(ArgumentFilter<?, ?> argFilter, RBaseNode callObj, RError.Message message, Object... messageArgs) {
-            castBuilder().insert(index(), FilterNode.create(argFilter, false, callObj, message, messageArgs, boxPrimitives));
+            castBuilder().insert(index(), () -> FilterNode.create(argFilter, false, callObj, message, messageArgs, boxPrimitives));
         }
 
         void mustBe(ArgumentFilter<?, ?> argFilter) {
@@ -1406,7 +1512,7 @@ public final class CastBuilder {
         }
 
         void shouldBe(ArgumentFilter<?, ?> argFilter, RBaseNode callObj, RError.Message message, Object... messageArgs) {
-            castBuilder().insert(index(), FilterNode.create(argFilter, true, callObj, message, messageArgs, boxPrimitives));
+            castBuilder().insert(index(), () -> FilterNode.create(argFilter, true, callObj, message, messageArgs, boxPrimitives));
         }
 
         void shouldBe(ArgumentFilter<?, ?> argFilter) {
@@ -1476,19 +1582,19 @@ public final class CastBuilder {
         }
 
         default <S> InitialPhaseBuilder<S> map(ArgumentMapper<T, S> mapFn) {
-            state().castBuilder().insert(state().index(), MapNode.create(mapFn));
+            state().castBuilder().insert(state().index(), () -> MapNode.create(mapFn));
             return state().factory.newInitialPhaseBuilder(this);
         }
 
         @SuppressWarnings("overloads")
         default <S, R> InitialPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, ArgumentMapper<S, R> trueBranchMapper) {
-            state().castBuilder().insert(state().index(), ConditionalMapNode.create(argFilter, MapNode.create(trueBranchMapper), null));
+            state().castBuilder().insert(state().index(), () -> ConditionalMapNode.create(argFilter, MapNode.create(trueBranchMapper), null));
 
             return state().factory.newInitialPhaseBuilder(this);
         }
 
-        default <S, R> InitialPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, CastNode trueBranchNode) {
-            state().castBuilder().insert(state().index(), ConditionalMapNode.create(argFilter, trueBranchNode, null));
+        default <S, R> InitialPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, CastNodeFactory trueBranchNodeFact) {
+            state().castBuilder().insert(state().index(), () -> ConditionalMapNode.create(argFilter, trueBranchNodeFact.create(), null));
 
             return state().factory.newInitialPhaseBuilder(this);
         }
@@ -1497,21 +1603,21 @@ public final class CastBuilder {
         default <S, R> InitialPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, ArgumentMapper<S, R> trueBranchMapper, ArgumentMapper<T, T> falseBranchMapper) {
             state().castBuilder().insert(
                             state().index(),
-                            ConditionalMapNode.create(argFilter, MapNode.create(trueBranchMapper),
+                            () -> ConditionalMapNode.create(argFilter, MapNode.create(trueBranchMapper),
                                             MapNode.create(falseBranchMapper)));
 
             return state().factory.newInitialPhaseBuilder(this);
         }
 
-        default <S, R> InitialPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, CastNode trueBranchNode, CastNode falseBranchNode) {
-            state().castBuilder().insert(state().index(), ConditionalMapNode.create(argFilter, trueBranchNode, falseBranchNode));
+        default <S, R> InitialPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, CastNodeFactory trueBranchNodeFact, CastNodeFactory falseBranchNodeFact) {
+            state().castBuilder().insert(state().index(), () -> ConditionalMapNode.create(argFilter, trueBranchNodeFact.create(), falseBranchNodeFact.create()));
 
             return state().factory.newInitialPhaseBuilder(this);
         }
 
         @SuppressWarnings("overloads")
         default <S, R> InitialPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, Function<ArgCastBuilder<T, ?>, CastNode> trueBranchNodeFactory) {
-            state().castBuilder().insert(state().index(), ConditionalMapNode.create(argFilter, trueBranchNodeFactory.apply(this), null));
+            state().castBuilder().insert(state().index(), () -> ConditionalMapNode.create(argFilter, trueBranchNodeFactory.apply(this), null));
 
             return state().factory.newInitialPhaseBuilder(this);
         }
@@ -1519,33 +1625,33 @@ public final class CastBuilder {
         @SuppressWarnings("overloads")
         default <S, R> InitialPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, Function<ArgCastBuilder<T, ?>, CastNode> trueBranchNodeFactory,
                         Function<ArgCastBuilder<T, ?>, CastNode> falseBranchNodeFactory) {
-            state().castBuilder().insert(state().index(), ConditionalMapNode.create(argFilter, trueBranchNodeFactory.apply(this), falseBranchNodeFactory.apply(this)));
+            state().castBuilder().insert(state().index(), () -> ConditionalMapNode.create(argFilter, trueBranchNodeFactory.apply(this), falseBranchNodeFactory.apply(this)));
 
             return state().factory.newInitialPhaseBuilder(this);
         }
 
         default InitialPhaseBuilder<T> notNA(RBaseNode callObj, RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), NonNANodeGen.create(callObj, message, messageArgs, null));
+            state().castBuilder().insert(state().index(), () -> NonNANodeGen.create(callObj, message, messageArgs, null));
             return this;
         }
 
         default InitialPhaseBuilder<T> notNA(RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), NonNANodeGen.create(null, message, messageArgs, null));
+            state().castBuilder().insert(state().index(), () -> NonNANodeGen.create(null, message, messageArgs, null));
             return this;
         }
 
         default InitialPhaseBuilder<T> notNA(T naReplacement, RBaseNode callObj, RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), NonNANodeGen.create(callObj, message, messageArgs, naReplacement));
+            state().castBuilder().insert(state().index(), () -> NonNANodeGen.create(callObj, message, messageArgs, naReplacement));
             return this;
         }
 
         default InitialPhaseBuilder<T> notNA(T naReplacement, RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), NonNANodeGen.create(null, message, messageArgs, naReplacement));
+            state().castBuilder().insert(state().index(), () -> NonNANodeGen.create(null, message, messageArgs, naReplacement));
             return this;
         }
 
         default InitialPhaseBuilder<T> notNA(T naReplacement) {
-            state().castBuilder().insert(state().index(), NonNANodeGen.create(naReplacement));
+            state().castBuilder().insert(state().index(), () -> NonNANodeGen.create(naReplacement));
             return this;
         }
 
@@ -1554,7 +1660,7 @@ public final class CastBuilder {
          * Example: {@code casts.arg("x").notNA()}.
          */
         default InitialPhaseBuilder<T> notNA() {
-            state().castBuilder().insert(state().index(), NonNANodeGen.create(state().defaultError().callObj, state().defaultError().message, state().defaultError().args, null));
+            state().castBuilder().insert(state().index(), () -> NonNANodeGen.create(state().defaultError().callObj, state().defaultError().message, state().defaultError().args, null));
             return this;
         }
 
@@ -1577,7 +1683,7 @@ public final class CastBuilder {
         }
 
         default CoercedPhaseBuilder<RAbstractDoubleVector, Byte> asLogicalVector(boolean preserveNames, boolean dimensionsPreservation, boolean attrPreservation) {
-            state().castBuilder().insert(state().index(), CastLogicalNodeGen.create(preserveNames, dimensionsPreservation, attrPreservation));
+            state().castBuilder().insert(state().index(), () -> CastLogicalNodeGen.create(preserveNames, dimensionsPreservation, attrPreservation));
             return state().factory.newCoercedPhaseBuilder(this, Byte.class);
         }
 
@@ -1622,6 +1728,83 @@ public final class CastBuilder {
 
     }
 
+    public interface PreinitialPhaseBuilder<T> extends InitialPhaseBuilder<T> {
+
+        default InitialPhaseBuilder<T> conf(Function<PipelineConfigBuilder, PipelineConfigBuilder> cfgLambda) {
+            cfgLambda.apply(getPipelineConfigBuilder());
+            return this;
+        }
+
+        default InitialPhaseBuilder<T> allowNull() {
+            return conf(c -> c.allowNull());
+        }
+
+        default InitialPhaseBuilder<T> mustNotBeNull() {
+            return conf(c -> c.mustNotBeNull(state().defaultError().callObj, state().defaultError().message, state().defaultError().args));
+        }
+
+        default InitialPhaseBuilder<T> mustNotBeNull(RError.Message errorMsg, Object... msgArgs) {
+            return conf(c -> c.mustNotBeNull(null, errorMsg, msgArgs));
+        }
+
+        default InitialPhaseBuilder<T> mustNotBeNull(RBaseNode callObj, RError.Message errorMsg, Object... msgArgs) {
+            return conf(c -> c.mustNotBeNull(callObj, errorMsg, msgArgs));
+        }
+
+        default InitialPhaseBuilder<T> mapNull(ArgumentMapper<? super RNull, ?> mapper) {
+            return conf(c -> c.mapNull(mapper));
+        }
+
+        default InitialPhaseBuilder<T> allowMissing() {
+            return conf(c -> c.allowMissing());
+        }
+
+        default InitialPhaseBuilder<T> mustNotBeMissing() {
+            return conf(c -> c.mustNotBeMissing(state().defaultError().callObj, state().defaultError().message, state().defaultError().args));
+        }
+
+        default InitialPhaseBuilder<T> mustNotBeMissing(RError.Message errorMsg, Object... msgArgs) {
+            return conf(c -> c.mustNotBeMissing(null, errorMsg, msgArgs));
+        }
+
+        default InitialPhaseBuilder<T> mustNotBeMissing(RBaseNode callObj, RError.Message errorMsg, Object... msgArgs) {
+            return conf(c -> c.mustNotBeMissing(callObj, errorMsg, msgArgs));
+        }
+
+        default InitialPhaseBuilder<T> mapMissing(ArgumentMapper<? super RMissing, ?> mapper) {
+            return conf(c -> c.mapMissing(mapper));
+        }
+
+        default InitialPhaseBuilder<T> allowNullAndMissing() {
+            return conf(c -> c.allowMissing().allowNull());
+        }
+
+        @Override
+        default PreinitialPhaseBuilder<T> defaultError(RBaseNode callObj, RError.Message message, Object... args) {
+            state().setDefaultError(callObj, message, args);
+            getPipelineConfigBuilder().updateDefaultError();
+            return this;
+        }
+
+        @Override
+        default PreinitialPhaseBuilder<T> defaultError(RError.Message message, Object... args) {
+            return defaultError(null, message, args);
+        }
+
+        @Override
+        default PreinitialPhaseBuilder<T> defaultWarning(RBaseNode callObj, RError.Message message, Object... args) {
+            state().setDefaultWarning(callObj, message, args);
+            return this;
+        }
+
+        @Override
+        default PreinitialPhaseBuilder<T> defaultWarning(RError.Message message, Object... args) {
+            return defaultWarning(null, message, args);
+        }
+
+        PipelineConfigBuilder getPipelineConfigBuilder();
+    }
+
     public interface CoercedPhaseBuilder<T extends RAbstractVector, S> extends ArgCastBuilder<T, CoercedPhaseBuilder<T, S>> {
 
         /**
@@ -1629,12 +1812,12 @@ public final class CastBuilder {
          * reports the warning message.
          */
         default HeadPhaseBuilder<S> findFirst(S defaultValue, RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), FindFirstNodeGen.create(elementClass(), null, message, messageArgs, defaultValue));
+            state().castBuilder().insert(state().index(), () -> FindFirstNodeGen.create(elementClass(), null, message, messageArgs, defaultValue));
             return state().factory.newHeadPhaseBuilder(this);
         }
 
         default HeadPhaseBuilder<S> findFirst(S defaultValue, RBaseNode callObj, RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), FindFirstNodeGen.create(elementClass(), callObj, message, messageArgs, defaultValue));
+            state().castBuilder().insert(state().index(), () -> FindFirstNodeGen.create(elementClass(), callObj, message, messageArgs, defaultValue));
             return state().factory.newHeadPhaseBuilder(this);
         }
 
@@ -1642,12 +1825,12 @@ public final class CastBuilder {
          * The inserted cast node raises an error if the input vector is empty.
          */
         default HeadPhaseBuilder<S> findFirst(RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), FindFirstNodeGen.create(elementClass(), null, message, messageArgs, null));
+            state().castBuilder().insert(state().index(), () -> FindFirstNodeGen.create(elementClass(), null, message, messageArgs, null));
             return state().factory.newHeadPhaseBuilder(this);
         }
 
         default HeadPhaseBuilder<S> findFirst(RBaseNode callObj, RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), FindFirstNodeGen.create(elementClass(), callObj, message, messageArgs, null));
+            state().castBuilder().insert(state().index(), () -> FindFirstNodeGen.create(elementClass(), callObj, message, messageArgs, null));
             return state().factory.newHeadPhaseBuilder(this);
         }
 
@@ -1658,7 +1841,7 @@ public final class CastBuilder {
         default HeadPhaseBuilder<S> findFirst() {
             DefaultError err = state().isDefaultErrorDefined() ? state().defaultError() : new DefaultError(null, RError.Message.LENGTH_ZERO);
             state().castBuilder().insert(state().index(),
-                            FindFirstNodeGen.create(elementClass(), err.callObj, err.message, err.args, null));
+                            () -> FindFirstNodeGen.create(elementClass(), err.callObj, err.message, err.args, null));
             return state().factory.newHeadPhaseBuilder(this);
         }
 
@@ -1668,7 +1851,7 @@ public final class CastBuilder {
          */
         default HeadPhaseBuilder<S> findFirst(S defaultValue) {
             assert defaultValue != null : "defaultValue cannot be null";
-            state().castBuilder().insert(state().index(), FindFirstNodeGen.create(elementClass(), defaultValue));
+            state().castBuilder().insert(state().index(), () -> FindFirstNodeGen.create(elementClass(), defaultValue));
             return state().factory.newHeadPhaseBuilder(this);
         }
 
@@ -1693,19 +1876,19 @@ public final class CastBuilder {
     public interface HeadPhaseBuilder<T> extends ArgCastBuilder<T, HeadPhaseBuilder<T>> {
 
         default <S> HeadPhaseBuilder<S> map(ArgumentMapper<T, S> mapFn) {
-            state().castBuilder().insert(state().index(), MapNode.create(mapFn));
+            state().castBuilder().insert(state().index(), () -> MapNode.create(mapFn));
             return state().factory.newHeadPhaseBuilder(this);
         }
 
         @SuppressWarnings("overloads")
         default <S, R> HeadPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, ArgumentMapper<S, R> trueBranchMapper) {
-            state().castBuilder().insert(state().index(), ConditionalMapNode.create(argFilter, MapNode.create(trueBranchMapper), null));
+            state().castBuilder().insert(state().index(), () -> ConditionalMapNode.create(argFilter, MapNode.create(trueBranchMapper), null));
 
             return state().factory.newHeadPhaseBuilder(this);
         }
 
-        default <S, R> HeadPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, CastNode trueBranchNode) {
-            state().castBuilder().insert(state().index(), ConditionalMapNode.create(argFilter, trueBranchNode, null));
+        default <S, R> HeadPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, CastNodeFactory trueBranchNodeFact) {
+            state().castBuilder().insert(state().index(), () -> ConditionalMapNode.create(argFilter, trueBranchNodeFact.create(), null));
 
             return state().factory.newHeadPhaseBuilder(this);
         }
@@ -1714,7 +1897,7 @@ public final class CastBuilder {
         default <S, R> HeadPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, ArgumentMapper<S, R> trueBranchMapper, ArgumentMapper<T, T> falseBranchMapper) {
             state().castBuilder().insert(
                             state().index(),
-                            ConditionalMapNode.create(argFilter, MapNode.create(trueBranchMapper),
+                            () -> ConditionalMapNode.create(argFilter, MapNode.create(trueBranchMapper),
                                             MapNode.create(falseBranchMapper)));
 
             return state().factory.newHeadPhaseBuilder(this);
@@ -1722,7 +1905,7 @@ public final class CastBuilder {
 
         @SuppressWarnings("overloads")
         default <S, R> HeadPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, Function<ArgCastBuilder<T, ?>, CastNode> trueBranchNodeFactory) {
-            state().castBuilder().insert(state().index(), ConditionalMapNode.create(argFilter, trueBranchNodeFactory.apply(this), null));
+            state().castBuilder().insert(state().index(), () -> ConditionalMapNode.create(argFilter, trueBranchNodeFactory.apply(this), null));
 
             return state().factory.newHeadPhaseBuilder(this);
         }
@@ -1730,13 +1913,13 @@ public final class CastBuilder {
         @SuppressWarnings("overloads")
         default <S, R> HeadPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, Function<ArgCastBuilder<T, ?>, CastNode> trueBranchNodeFactory,
                         Function<ArgCastBuilder<T, ?>, CastNode> falseBranchNodeFactory) {
-            state().castBuilder().insert(state().index(), ConditionalMapNode.create(argFilter, trueBranchNodeFactory.apply(this), falseBranchNodeFactory.apply(this)));
+            state().castBuilder().insert(state().index(), () -> ConditionalMapNode.create(argFilter, trueBranchNodeFactory.apply(this), falseBranchNodeFactory.apply(this)));
 
             return state().factory.newHeadPhaseBuilder(this);
         }
 
-        default <S, R> HeadPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, CastNode trueBranchNode, CastNode falseBranchNode) {
-            state().castBuilder().insert(state().index(), ConditionalMapNode.create(argFilter, trueBranchNode, falseBranchNode));
+        default <S, R> HeadPhaseBuilder<Object> mapIf(ArgumentFilter<? super T, S> argFilter, CastNodeFactory trueBranchNodeFact, CastNodeFactory falseBranchNodeFact) {
+            state().castBuilder().insert(state().index(), () -> ConditionalMapNode.create(argFilter, trueBranchNodeFact.create(), falseBranchNodeFact.create()));
 
             return state().factory.newHeadPhaseBuilder(this);
         }
@@ -1781,32 +1964,32 @@ public final class CastBuilder {
         }
 
         default HeadPhaseBuilder<T> notNA(RBaseNode callObj, RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), NonNANodeGen.create(callObj, message, messageArgs, null));
+            state().castBuilder().insert(state().index(), () -> NonNANodeGen.create(callObj, message, messageArgs, null));
             return this;
         }
 
         default HeadPhaseBuilder<T> notNA(RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), NonNANodeGen.create(null, message, messageArgs, null));
+            state().castBuilder().insert(state().index(), () -> NonNANodeGen.create(null, message, messageArgs, null));
             return this;
         }
 
         default HeadPhaseBuilder<T> notNA(T naReplacement, RBaseNode callObj, RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), NonNANodeGen.create(callObj, message, messageArgs, naReplacement));
+            state().castBuilder().insert(state().index(), () -> NonNANodeGen.create(callObj, message, messageArgs, naReplacement));
             return this;
         }
 
         default HeadPhaseBuilder<T> notNA(T naReplacement, RError.Message message, Object... messageArgs) {
-            state().castBuilder().insert(state().index(), NonNANodeGen.create(null, message, messageArgs, naReplacement));
+            state().castBuilder().insert(state().index(), () -> NonNANodeGen.create(null, message, messageArgs, naReplacement));
             return this;
         }
 
         default HeadPhaseBuilder<T> notNA() {
-            state().castBuilder().insert(state().index(), NonNANodeGen.create(state().defaultError().callObj, state().defaultError().message, state().defaultError().args, null));
+            state().castBuilder().insert(state().index(), () -> NonNANodeGen.create(state().defaultError().callObj, state().defaultError().message, state().defaultError().args, null));
             return this;
         }
 
         default HeadPhaseBuilder<T> notNA(T naReplacement) {
-            state().castBuilder().insert(state().index(), NonNANodeGen.create(naReplacement));
+            state().castBuilder().insert(state().index(), () -> NonNANodeGen.create(naReplacement));
             return this;
         }
 
@@ -1823,8 +2006,8 @@ public final class CastBuilder {
         }
 
         @Override
-        public InitialPhaseBuilderImpl<Object> newInitialPhaseBuilder() {
-            return new InitialPhaseBuilderImpl<>();
+        public PreinitialPhaseBuilderImpl<Object> newPreinitialPhaseBuilder() {
+            return new PreinitialPhaseBuilderImpl<>();
         }
 
         @Override
@@ -1847,9 +2030,25 @@ public final class CastBuilder {
                 super(new ArgCastBuilderState(state, false));
             }
 
-            InitialPhaseBuilderImpl() {
+        }
+
+        public final class PreinitialPhaseBuilderImpl<T> extends ArgCastBuilderBase<T, InitialPhaseBuilder<T>> implements PreinitialPhaseBuilder<T> {
+
+            PreinitialPhaseBuilderImpl() {
                 super(new ArgCastBuilderState(argumentIndex, argumentName, ArgCastBuilderFactoryImpl.this, CastBuilder.this, false));
+
+                if (argumentIndex >= pipelineCfgBuilders.length) {
+                    pipelineCfgBuilders = Arrays.copyOf(pipelineCfgBuilders, argumentIndex + 1);
+                }
+
+                pipelineCfgBuilders[argumentIndex] = new PipelineConfigBuilder(state());
+            }
+
+            @Override
+            public PipelineConfigBuilder getPipelineConfigBuilder() {
+                return pipelineCfgBuilders[argumentIndex];
             }
+
         }
 
         public final class CoercedPhaseBuilderImpl<T extends RAbstractVector, S> extends ArgCastBuilderBase<T, CoercedPhaseBuilder<T, S>> implements CoercedPhaseBuilder<T, S> {
@@ -1884,9 +2083,7 @@ public final class CastBuilder {
 
         private Function<ArgCastBuilder<T, ?>, CastNode> makeChain(Function<ArgCastBuilder<T, ?>, CastNode> secondCastNodeFactory) {
             return phaseBuilder -> {
-                CastNode firstCast = firstCastNodeFactory.apply(phaseBuilder);
-                CastNode secondCast = secondCastNodeFactory.apply(phaseBuilder);
-                return new ChainedCastNode(firstCast, secondCast);
+                return new ChainedCastNode(() -> firstCastNodeFactory.apply(phaseBuilder), () -> secondCastNodeFactory.apply(phaseBuilder));
             };
         }
 
@@ -1978,4 +2175,98 @@ public final class CastBuilder {
 
     }
 
+    public static final class PipelineConfigBuilder {
+
+        private final ArgCastBuilderState state;
+
+        private ArgumentMapper<? super RMissing, ?> missingMapper = null;
+        private ArgumentMapper<? super RNull, ?> nullMapper = null;
+        private DefaultError missingMsg;
+        private DefaultError nullMsg;
+
+        public PipelineConfigBuilder(ArgCastBuilderState state) {
+            this.state = state;
+            missingMsg = state.defaultError();
+            nullMsg = state.defaultError();
+        }
+
+        public String getArgName() {
+            return state.argumentName;
+        }
+
+        public ArgumentMapper<? super RMissing, ?> getMissingMapper() {
+            return missingMapper;
+        }
+
+        public ArgumentMapper<? super RNull, ?> getNullMapper() {
+            return nullMapper;
+        }
+
+        public DefaultError getMissingMessage() {
+            return missingMsg;
+        }
+
+        public DefaultError getNullMessage() {
+            return nullMsg;
+        }
+
+        public PipelineConfigBuilder mustNotBeMissing(RBaseNode callObj, RError.Message errorMsg, Object... msgArgs) {
+            missingMapper = null;
+            missingMsg = new DefaultError(callObj, errorMsg, msgArgs);
+            return this;
+        }
+
+        public PipelineConfigBuilder mapMissing(ArgumentMapper<? super RMissing, ?> mapper) {
+            missingMapper = mapper;
+            missingMsg = null;
+            return this;
+        }
+
+        public PipelineConfigBuilder mapMissing(ArgumentMapper<? super RMissing, ?> mapper, RBaseNode callObj, RError.Message warningMsg, Object... msgArgs) {
+            missingMapper = mapper;
+            missingMsg = new DefaultError(callObj, warningMsg, msgArgs);
+            return this;
+        }
+
+        public PipelineConfigBuilder allowMissing() {
+            return mapMissing(Predef.missingConstant());
+        }
+
+        public PipelineConfigBuilder allowMissing(RBaseNode callObj, RError.Message warningMsg, Object... msgArgs) {
+            return mapMissing(Predef.missingConstant(), callObj, warningMsg, msgArgs);
+        }
+
+        public PipelineConfigBuilder mustNotBeNull(RBaseNode callObj, RError.Message errorMsg, Object... msgArgs) {
+            nullMapper = null;
+            nullMsg = new DefaultError(callObj, errorMsg, msgArgs);
+            return this;
+        }
+
+        public PipelineConfigBuilder mapNull(ArgumentMapper<? super RNull, ?> mapper) {
+            nullMapper = mapper;
+            nullMsg = null;
+            return this;
+        }
+
+        public PipelineConfigBuilder mapNull(ArgumentMapper<? super RNull, ?> mapper, RBaseNode callObj, RError.Message warningMsg, Object... msgArgs) {
+            nullMapper = mapper;
+            nullMsg = new DefaultError(callObj, warningMsg, msgArgs);
+            return this;
+        }
+
+        public PipelineConfigBuilder allowNull() {
+            return mapNull(Predef.nullConstant());
+        }
+
+        public PipelineConfigBuilder allowNull(RBaseNode callObj, RError.Message warningMsg, Object... msgArgs) {
+            return mapNull(Predef.nullConstant(), callObj, warningMsg, msgArgs);
+        }
+
+        void updateDefaultError() {
+            missingMsg = state.defaultError();
+            nullMsg = state.defaultError();
+        }
+
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/BypassNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/BypassNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..61293070acc79514450eb0238d59fbfd593903ae
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/BypassNode.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2016, 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.unary;
+
+import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.builtin.ArgumentMapper;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder.DefaultError;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder.PipelineConfigBuilder;
+import com.oracle.truffle.r.runtime.data.RMissing;
+import com.oracle.truffle.r.runtime.data.RNull;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public abstract class BypassNode extends CastNode {
+
+    private final boolean isRNullBypassed;
+    private final DefaultError nullMsg;
+    private final ArgumentMapper nullMapFn;
+
+    private final boolean isRMissingBypassed;
+    private final DefaultError missingMsg;
+    private final ArgumentMapper missingMapFn;
+    private final boolean noHead;
+
+    @Child private CastNode wrappedHead;
+    @Child private CastNode directFindFirstNode;
+    private final boolean useDirectFindFirstNode;
+
+    protected BypassNode(PipelineConfigBuilder pcb, CastNode wrappedHead) {
+        this.nullMapFn = pcb.getNullMapper();
+        this.isRNullBypassed = this.nullMapFn != null;
+        this.nullMsg = pcb.getNullMessage() == null ? null : pcb.getNullMessage().fixCallObj(this);
+
+        this.missingMapFn = pcb.getMissingMapper();
+        this.isRMissingBypassed = this.missingMapFn != null;
+        this.missingMsg = pcb.getMissingMessage() == null ? null : pcb.getMissingMessage().fixCallObj(this);
+
+        this.wrappedHead = wrappedHead;
+        this.noHead = wrappedHead == null;
+
+        assert this.nullMsg != null || this.isRNullBypassed;
+        assert this.missingMsg != null || this.isRMissingBypassed;
+
+        this.directFindFirstNode = !isRNullBypassed || !isRMissingBypassed ? createDirectFindFirstNode(wrappedHead) : null;
+        this.useDirectFindFirstNode = directFindFirstNode != null;
+    }
+
+    public static CastNode create(PipelineConfigBuilder pcb, CastNode wrappedHead) {
+        return BypassNodeGen.create(pcb, wrappedHead);
+    }
+
+    public CastNode getWrappedHead() {
+        return wrappedHead;
+    }
+
+    public ArgumentMapper getNullMapper() {
+        return nullMapFn;
+    }
+
+    public ArgumentMapper getMissingMapper() {
+        return missingMapFn;
+    }
+
+    @Specialization
+    public Object bypassRNull(RNull x) {
+        if (isRNullBypassed) {
+            if (nullMsg != null) {
+                handleArgumentWarning(x, nullMsg.callObj, nullMsg.message, nullMsg.args);
+            }
+            return nullMapFn.map(x);
+        } else if (useDirectFindFirstNode) {
+            return directFindFirstNode.execute(x);
+        } else {
+            handleArgumentError(x, nullMsg.callObj, nullMsg.message, nullMsg.args);
+            return x;
+        }
+    }
+
+    @Specialization
+    public Object bypassRMissing(RMissing x) {
+        if (isRMissingBypassed) {
+            if (missingMsg != null) {
+                handleArgumentWarning(x, missingMsg.callObj, missingMsg.message, missingMsg.args);
+            }
+            return missingMapFn.map(x);
+        } else if (useDirectFindFirstNode) {
+            return directFindFirstNode.execute(x);
+        } else {
+            handleArgumentError(x, missingMsg.callObj, missingMsg.message, missingMsg.args);
+            return x;
+        }
+    }
+
+    @Fallback
+    public Object handleOthers(Object x) {
+        return noHead ? x : wrappedHead.execute(x);
+    }
+
+    static CastNode createDirectFindFirstNode(CastNode wrappedHead) {
+        ChainedCastNode parentFfh = null;
+        ChainedCastNode ffh = null;
+
+        if (wrappedHead != null) {
+            CastNode cn = wrappedHead;
+            while (cn instanceof ChainedCastNode) {
+                ChainedCastNode chcn = (ChainedCastNode) cn;
+                if (chcn.getSecondCast() instanceof FindFirstNode) {
+                    FindFirstNode ffn = (FindFirstNode) chcn.getSecondCast();
+                    if (ffn.getDefaultValue() != null) {
+                        ffh = chcn;
+                    }
+                    break;
+                }
+                parentFfh = chcn;
+                cn = chcn.getFirstCast();
+            }
+        }
+
+        if (ffh == null) {
+            return null;
+        } else if (parentFfh == null) {
+            return ffh.getSecondCastFact().create();
+        } else {
+            return new ChainedCastNode(ffh.getSecondCastFact(), parentFfh.getSecondCastFact());
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastNode.java
index 463283d4f62ec3068a9dc0f947249dc5457121b8..0ac32cf1e3721dcc47d229734ceb24ac7eea6f19 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastNode.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.unary;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.context.RContext;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ChainedCastNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ChainedCastNode.java
index 6497ce2d999787c72eab7460b2db9add5ca82a16..e2145e7b63569a0ed18aaff8d7be5546f64b04b1 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ChainedCastNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ChainedCastNode.java
@@ -24,16 +24,22 @@ package com.oracle.truffle.r.nodes.unary;
 
 import com.oracle.truffle.api.nodes.NodeCost;
 import com.oracle.truffle.api.nodes.NodeInfo;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder.CastNodeFactory;
 
 @NodeInfo(cost = NodeCost.NONE)
 public final class ChainedCastNode extends CastNode {
 
+    private final CastNodeFactory firstCastFact;
+    private final CastNodeFactory secondCastFact;
+
     @Child private CastNode firstCast;
     @Child private CastNode secondCast;
 
-    public ChainedCastNode(CastNode firstCast, CastNode secondCast) {
-        this.firstCast = firstCast;
-        this.secondCast = secondCast;
+    public ChainedCastNode(CastNodeFactory firstCastFact, CastNodeFactory secondCastFact) {
+        this.firstCastFact = firstCastFact;
+        this.secondCastFact = secondCastFact;
+        this.firstCast = firstCastFact.create();
+        this.secondCast = secondCastFact.create();
     }
 
     @Override
@@ -48,4 +54,12 @@ public final class ChainedCastNode extends CastNode {
     public CastNode getSecondCast() {
         return secondCast;
     }
+
+    public CastNodeFactory getFirstCastFact() {
+        return firstCastFact;
+    }
+
+    public CastNodeFactory getSecondCastFact() {
+        return secondCastFact;
+    }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_col.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_col.java
index e279cf63709bc115079deccc20229bc256f1a964..5f2cad29df2c8a3caf5c32fa8d54080af1870187 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_col.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_col.java
@@ -32,11 +32,11 @@ public class TestBuiltin_col extends TestBase {
         assertEval("{ ma <- matrix(1:12, 3, 4) ; col(ma) }");
         assertEval("{ ma <- cbind(x = 1:10, y = (-4:5)^2) ; col(ma) }");
 
-        assertEval(Output.IgnoreErrorContext, "{ col(c(1,2,3)) }");
+        assertEval("{ col(c(1,2,3)) }");
     }
 
     @Test
     public void testCasts0() {
-        assertEval(Output.IgnoreErrorContext, "col(NULL)");
+        assertEval("col(NULL)");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_listfiles.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_listfiles.java
index 7058a42604c4499aa234492fedd22d77a83361e3..6b11db7b2dfe50eb3a22d6501181fb51f19067d6 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_listfiles.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_listfiles.java
@@ -30,7 +30,8 @@ public class TestBuiltin_listfiles extends TestBase {
     @Test
     public void testlistfiles3() {
         // FastR bug; not recursing in to "."
-        assertEval("argv <- list('.', '^CITATION.*', FALSE, FALSE, TRUE, FALSE, FALSE, FALSE); .Internal(list.files(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]], argv[[8]]))");
+        assertEval(Ignored.Unknown,
+                        "argv <- list('.', '^CITATION.*', FALSE, FALSE, TRUE, FALSE, FALSE, FALSE); .Internal(list.files(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]], argv[[8]]))");
     }
 
     @Test