diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/DevicesCCalls.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/DevicesCCalls.java
index d46eed38a1d4717ccfb0a50185d8012722157f79..539994d1f72cc6389624c2d03b341aaf0d206a1f 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/DevicesCCalls.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/DevicesCCalls.java
@@ -23,7 +23,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.library.grDevices.DevicesCCallsFactory.C_DevOffNodeGen;
 import com.oracle.truffle.r.library.grDevices.pdf.PdfGraphicsDevice;
 import com.oracle.truffle.r.library.graphics.core.GraphicsEngineImpl;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
@@ -36,8 +35,8 @@ public class DevicesCCalls {
             return C_DevOffNodeGen.create();
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(C_DevOff.class);
             casts.arg(0).asIntegerVector().findFirst();
         }
 
@@ -65,6 +64,10 @@ public class DevicesCCalls {
         @Child private CastNode asLogicalNode;
         @Child private CastNode asIntNode;
 
+        static {
+            Casts.noCasts(C_PDF.class);
+        }
+
         public C_PDF() {
             asStringNode = newCastBuilder().asStringVector().findFirst().buildCastNode();
             asDoubleNode = newCastBuilder().asDoubleVector().findFirst().buildCastNode();
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/GraphicsCCalls.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/GraphicsCCalls.java
index dbfc4dc4d9dc533419da5ceeb0618a9298ad2108..695ba86dbbfa3af1761cecfaba525de6ed53f736 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/GraphicsCCalls.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/GraphicsCCalls.java
@@ -37,6 +37,10 @@ public class GraphicsCCalls {
     public static final class C_PlotXY extends RExternalBuiltinNode {
         @Child private CastNode castXYNode;
 
+        static {
+            Casts.noCasts(C_PlotXY.class);
+        }
+
         public C_PlotXY() {
             castXYNode = newCastBuilder().mustBe(doubleValue().and(size(2))).asDoubleVector().buildCastNode();
         }
@@ -79,6 +83,10 @@ public class GraphicsCCalls {
 
     public static final class C_Par extends RExternalBuiltinNode {
 
+        static {
+            Casts.noCasts(C_Par.class);
+        }
+
         @Override
         @TruffleBoundary
         public Object call(RArgsValuesAndNames args) {
@@ -101,6 +109,10 @@ public class GraphicsCCalls {
         private double font = RRuntime.DOUBLE_NA;
         @Child private CastNode firstDoubleCast;
 
+        static {
+            Casts.noCasts(C_mtext.class);
+        }
+
         public C_mtext() {
             firstDoubleCast = newCastBuilder().asDoubleVector().findFirst().buildCastNode();
         }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java
index ca5d398f2254e9c8d27908c53d18b498ca4ed1d2..6623a2c7ca6a8538ce7bbe35792f2b8f5c18294e 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java
@@ -17,7 +17,6 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
@@ -52,6 +51,10 @@ public class GridFunctions {
     public static final class KillGrid extends RExternalBuiltinNode {
         @Child GridRFFI.KillGridNode killGridNode = RFFIFactory.getRFFI().getGridRFFI().createKillGridNode();
 
+        static {
+            Casts.noCasts(KillGrid.class);
+        }
+
         @Override
         @TruffleBoundary
         public Object call(RArgsValuesAndNames args) {
@@ -60,8 +63,9 @@ public class GridFunctions {
     }
 
     public abstract static class ValidUnits extends RExternalBuiltinNode.Arg1 {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(ValidUnits.class);
             casts.arg(0).mustBe(stringValue(), RError.Message.GENERIC, "'units' must be character").asStringVector().mustBe(notEmpty(), RError.Message.GENERIC, "'units' must be of length > 0");
         }
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java
index 0fa12c99f3bf99aa9296822f540d775d524b2bac..ce07d50f5bc3879e1c777194002da7b8b15f6ae0 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java
@@ -33,7 +33,7 @@ import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
 import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyScalarNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyScalarNodeGen;
@@ -68,7 +68,8 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 public class MethodsListDispatch {
 
-    private static void checkSingleString(CastBuilder casts, int argNum, String argName, String msg, boolean nonEmpty, Function<Object, String> clsHierFn, Function<Object, Integer> vecLenFn) {
+    private static void checkSingleString(Casts casts, int argNum, String argName, String msg, boolean nonEmpty, Function<Object, String> clsHierFn,
+                    Function<Object, Integer> vecLenFn) {
         //@formatter:off
         casts.arg(argNum, argName).
             defaultError(RError.NO_CALLER, RError.Message.SINGLE_STRING_WRONG_TYPE, msg, clsHierFn).
@@ -82,6 +83,10 @@ public class MethodsListDispatch {
 
     public abstract static class R_initMethodDispatch extends RExternalBuiltinNode.Arg1 {
 
+        static {
+            Casts.noCasts(R_initMethodDispatch.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected REnvironment initMethodDispatch(REnvironment env) {
@@ -99,8 +104,8 @@ public class MethodsListDispatch {
 
     public abstract static class R_methodsPackageMetaName extends RExternalBuiltinNode.Arg3 {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(R_methodsPackageMetaName.class);
             Function<Object, String> clsHierFn = ClassHierarchyScalarNode::get;
             Function<Object, Integer> vecLenFn = arg -> ((RAbstractStringVector) arg).getLength();
 
@@ -122,14 +127,11 @@ public class MethodsListDispatch {
 
     public abstract static class R_getClassFromCache extends RExternalBuiltinNode.Arg2 {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            //@formatter:off
-            casts.arg(0, "klass").defaultError(RError.Message.GENERIC, "class should be either a character-string name or a class definition").
-                mustBe(stringValue().or(instanceOf(RS4Object.class)));
+        static {
+            Casts casts = new Casts(R_getClassFromCache.class);
+            casts.arg(0, "klass").defaultError(RError.Message.GENERIC, "class should be either a character-string name or a class definition").mustBe(stringValue().or(instanceOf(RS4Object.class)));
 
             casts.arg(1, "table").mustNotBeNull(RError.NO_CALLER, RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
-            //@formatter:on
         }
 
         protected GetFixedAttributeNode createPckgAttrAccess() {
@@ -175,8 +177,8 @@ public class MethodsListDispatch {
 
     public abstract static class R_set_method_dispatch extends RExternalBuiltinNode.Arg1 {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(R_set_method_dispatch.class);
             casts.arg(0).asLogicalVector().findFirst(RRuntime.LOGICAL_NA);
         }
 
@@ -200,6 +202,10 @@ public class MethodsListDispatch {
     public abstract static class R_M_setPrimitiveMethods extends RExternalBuiltinNode.Arg5 {
         @Child private AccessSlotNode accessSlotNode;
 
+        static {
+            Casts.noCasts(R_M_setPrimitiveMethods.class);
+        }
+
         private AccessSlotNode initAccessSlotNode() {
             if (accessSlotNode == null) {
                 accessSlotNode = insert(AccessSlotNodeGen.create(true));
@@ -289,6 +295,10 @@ public class MethodsListDispatch {
 
     public abstract static class R_identC extends RExternalBuiltinNode.Arg2 {
 
+        static {
+            Casts.noCasts(R_identC.class);
+        }
+
         @Specialization
         protected Object identC(RAbstractStringVector e1, RAbstractStringVector e2) {
             if (e1.getLength() == 1 && e2.getLength() == 1 && e1.getDataAt(0).equals(e2.getDataAt(0))) {
@@ -309,25 +319,18 @@ public class MethodsListDispatch {
 
         @Child private GetGenericInternal getGenericInternal = GetGenericInternalNodeGen.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(R_getGeneric.class);
             Function<Object, String> clsHierFn = ClassHierarchyScalarNode::get;
-
-            //@formatter:off
             Function<Object, Integer> vecLenFn = arg -> ((RAbstractStringVector) arg).getLength();
 
             checkSingleString(casts, 0, "f", "The argument \"f\" to getGeneric", true, clsHierFn, vecLenFn);
 
-            casts.arg(1, "mustFind").
-                asLogicalVector().
-                findFirst(RRuntime.LOGICAL_NA).
-                map(toBoolean());
+            casts.arg(1, "mustFind").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
 
-            casts.arg(2, "env").
-                mustBe(instanceOf(REnvironment.class));
+            casts.arg(2, "env").mustBe(instanceOf(REnvironment.class));
 
             checkSingleString(casts, 3, "package", "The argument \"package\" to getGeneric", false, clsHierFn, vecLenFn);
-            //@formatter:on
         }
 
         @Specialization
@@ -434,6 +437,10 @@ public class MethodsListDispatch {
         @Child private LocalReadVariableNode readDotNextMethod;
         @Child private LocalReadVariableNode readDots;
 
+        static {
+            Casts.noCasts(R_nextMethodCall.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected Object nextMethodCall(RLanguage matchedCall, REnvironment ev) {
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/Slot.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/Slot.java
index b1bc33c7996176213861630a55a533a4bdf19904..51803d72d1764bc80f4c6244ec3e2eec40ee7c1d 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/Slot.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/Slot.java
@@ -20,7 +20,6 @@ import com.oracle.truffle.r.nodes.access.AccessSlotNode;
 import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
 import com.oracle.truffle.r.nodes.access.UpdateSlotNode;
 import com.oracle.truffle.r.nodes.access.UpdateSlotNodeGen;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastToAttributableNode;
@@ -37,8 +36,8 @@ public class Slot {
         @Child private AccessSlotNode accessSlotNode = AccessSlotNodeGen.create(false);
         @Child private CastToAttributableNode castAttributable = CastToAttributableNodeGen.create(true, true, true);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(R_getSlot.class);
             casts.arg(1, "name").defaultError(RError.NO_CALLER, RError.Message.GENERIC, "invalid type or length for slot name").mustBe(stringValue()).asStringVector().mustBe(
                             singleElement()).findFirst().mustBe(Predef.lengthGt(0), RError.NO_CALLER, RError.Message.ZERO_LENGTH_VARIABLE);
         }
@@ -65,8 +64,8 @@ public class Slot {
         @Child private UpdateSlotNode updateSlotNode = UpdateSlotNodeGen.create();
         @Child private CastToAttributableNode castAttributable = CastToAttributableNodeGen.create(true, true, true);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(R_setSlot.class);
             casts.arg(1, "name").defaultError(RError.NO_CALLER, RError.Message.GENERIC, "invalid type or length for slot name").mustBe(stringValue()).asStringVector().mustBe(
                             singleElement()).findFirst().mustBe(Predef.lengthGt(0), RError.NO_CALLER, RError.Message.ZERO_LENGTH_VARIABLE);
         }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/SubstituteDirect.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/SubstituteDirect.java
index 10d1a2d64a118f833b65410ea08c6c0f6f205510..420e634f2eec1004e63bb29298614c0ca00c9f7b 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/SubstituteDirect.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/SubstituteDirect.java
@@ -38,6 +38,10 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 
 public abstract class SubstituteDirect extends RExternalBuiltinNode.Arg2 {
 
+    static {
+        Casts.noCasts(SubstituteDirect.class);
+    }
+
     @Specialization
     @TruffleBoundary
     protected static Object substituteDirect(Object object, REnvironment env) {
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/BinDist.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/BinDist.java
index 2df583879a906d0a99ce1ed127850e9ec01c904a..93fb0bd2f5829e9e47e8a6656ca1e9bf3c9326ea 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/BinDist.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/BinDist.java
@@ -38,8 +38,8 @@ public abstract class BinDist extends RExternalBuiltinNode.Arg5 {
         return BinDistNodeGen.create();
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(BinDist.class);
         casts.arg(0).asDoubleVector();
         casts.arg(1).asDoubleVector();
         casts.arg(2).asDoubleVector().findFirst();
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java
index 9664f3ba0886b898ed9862962c2e6e9a4a59c48c..be4422e729caa2e552fa45586ccb92bdd6a0dfad 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java
@@ -22,7 +22,6 @@ import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -38,8 +37,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
 
     @Child private GetFixedAttributeNode getNamesAttrNode = GetFixedAttributeNode.createNames();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Cdist.class);
         casts.arg(0).asDoubleVector();
         casts.arg(1).asIntegerVector().findFirst();
         casts.arg(2).mustBe(instanceOf(RList.class));
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java
index cf77a3c203e680ad2b1c9bd1cd2b32a37ceb0c08..ca606b38331ece53d38741ea3374379b24b950d2 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995, 1996  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1997-2013,  The R Core Team
- * Copyright (c) 2015, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -34,6 +34,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public final class CompleteCases extends RExternalBuiltinNode {
 
+    static {
+        Casts.noCasts(CompleteCases.class);
+    }
+
     private RError invalidType(Object entry) {
         throw RError.error(this, RError.Message.INVALID_TYPE_ARGUMENT, ((RTypedValue) entry).getRType().getName());
     }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java
index 84091dec27eee19d2a22c339693fc6ca95e964c0..05fc0538c7b25a639621064b0dea4015ba5a49b9 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java
@@ -23,7 +23,6 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -47,11 +46,11 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         this.isCor = isCor;
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Covcor.class);
         casts.arg(0).mustNotBeNull(SHOW_CALLER, Message.IS_NULL, "x").asDoubleVector();
         casts.arg(1).asDoubleVector();
-        casts.arg(2).asIntegerVector().findFirst().mustBe(eq(4), this, Message.NYI, "covcor: other method than 4 not implemented.");
+        casts.arg(2).asIntegerVector().findFirst().mustBe(eq(4), Message.NYI, "covcor: other method than 4 not implemented.");
         casts.arg(3).asLogicalVector().findFirst().map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java
index 2d19c386ca9008a469ccea7cbf6119c1eb27d93e..a2de828f383f45478803349ea5674253ff4a63f2 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java
@@ -13,7 +13,6 @@ package com.oracle.truffle.r.library.stats;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RIntVector;
@@ -23,8 +22,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 
 public abstract class Cutree extends RExternalBuiltinNode.Arg2 {
 
-    @Override
-    public void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Cutree.class);
         casts.arg(0).asIntegerVector();
         casts.arg(1).asIntegerVector();
     }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java
index 068f611650064146dc53d4a48a67b56d0da36a9b..0eb3928748d7e3ef7d7e41770d2f85d9ffd5e668 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java
@@ -13,15 +13,14 @@ package com.oracle.truffle.r.library.stats;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 
 public abstract class DoubleCentre extends RExternalBuiltinNode.Arg1 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(DoubleCentre.class);
         casts.arg(0).asDoubleVector();
     }
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java
index 98ea3435479b0dc1b3f02b745deb1598cd2588b9..c1ea604e1f543e23cfcc47a014e063141898a818 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java
@@ -24,7 +24,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.function.opt.ReuseNonSharedNode;
 import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode;
@@ -49,8 +48,8 @@ public abstract class RMultinomNode extends RExternalBuiltinNode.Arg3 {
         return RMultinomNodeGen.create();
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(RMultinomNode.class);
         casts.arg(0).asIntegerVector().findFirst().mustBe(notIntNA(), SHOW_CALLER, Message.INVALID_FIRST_ARGUMENT_NAME, "n");
         casts.arg(1).asIntegerVector().findFirst().mustBe(notIntNA(), SHOW_CALLER, Message.INVALID_SECOND_ARGUMENT_NAME, "size");
         casts.arg(2).asDoubleVector();
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java
index b977a267130d21e12493f03d2e3f12854d24bea3..14f9409f3ec099c5a45cfb569c74874686ec38a2 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java
@@ -31,7 +31,7 @@ import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunction
 import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunction2NodeGen;
 import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunction3NodeGen;
 import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
@@ -66,8 +66,8 @@ public final class RandFunctionsNodes {
 
     /**
      * Converts given value to actual length that should be used as length of the output vector. The
-     * argument must be cast using {@link #addLengthCast(CastBuilder)}. Using this node allows us to
-     * avoid casting of long vectors to integers if we only need to know their length.
+     * argument must be cast using {@link #addLengthCast(Casts)}. Using this node allows us to avoid
+     * casting of long vectors to integers if we only need to know their length.
      */
     protected abstract static class ConvertToLength extends Node {
         public abstract int execute(RAbstractVector value);
@@ -89,7 +89,7 @@ public final class RandFunctionsNodes {
             return vector.getLength();
         }
 
-        private static void addLengthCast(CastBuilder casts) {
+        private static void addLengthCast(Casts casts) {
             casts.arg(0).defaultError(SHOW_CALLER, INVALID_UNNAMED_ARGUMENTS).mustBe(abstractVectorValue()).asVector();
         }
     }
@@ -262,8 +262,8 @@ public final class RandFunctionsNodes {
             return RandFunction3NodeGen.create(RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen.create(function));
         }
 
-        @Override
-        protected final void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(RandFunction3Node.class);
             ConvertToLength.addLengthCast(casts);
             casts.arg(1).asDoubleVector();
             casts.arg(2).asDoubleVector();
@@ -292,8 +292,8 @@ public final class RandFunctionsNodes {
             return RandFunction2NodeGen.create(RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen.create(function));
         }
 
-        @Override
-        protected final void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(RandFunction2Node.class);
             ConvertToLength.addLengthCast(casts);
             casts.arg(1).asDoubleVector();
             casts.arg(2).asDoubleVector();
@@ -321,8 +321,8 @@ public final class RandFunctionsNodes {
             return RandFunction1NodeGen.create(RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen.create(function));
         }
 
-        @Override
-        protected final void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(RandFunction1Node.class);
             ConvertToLength.addLengthCast(casts);
             casts.arg(1).asDoubleVector();
         }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java
index 5ea680278a4d36207f0c5ecc3febd9e228d1da61..11a0662bdfafa8f80dd5bbb6728c4a0adbfc4c3f 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java
@@ -30,7 +30,6 @@ import com.oracle.truffle.r.library.stats.StatsFunctionsNodesFactory.Function3_2
 import com.oracle.truffle.r.library.stats.StatsFunctionsNodesFactory.Function4_1NodeGen;
 import com.oracle.truffle.r.library.stats.StatsFunctionsNodesFactory.Function4_2NodeGen;
 import com.oracle.truffle.r.nodes.attributes.UnaryCopyAttributesNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RError;
@@ -149,8 +148,8 @@ public final class StatsFunctionsNodes {
             return Function3_2NodeGen.create(function);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Function3_2Node.class);
             casts.arg(0).asDoubleVector();
             casts.arg(1).asDoubleVector();
             casts.arg(2).asDoubleVector();
@@ -177,8 +176,8 @@ public final class StatsFunctionsNodes {
             return Function4_1NodeGen.create(function);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Function4_1Node.class);
             casts.arg(0).asDoubleVector();
             casts.arg(1).asDoubleVector();
             casts.arg(2).asDoubleVector();
@@ -205,8 +204,8 @@ public final class StatsFunctionsNodes {
             return Function4_2NodeGen.create(function);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Function4_2Node.class);
             casts.arg(0).asDoubleVector();
             casts.arg(1).asDoubleVector();
             casts.arg(2).asDoubleVector();
@@ -234,8 +233,8 @@ public final class StatsFunctionsNodes {
             return Function3_1NodeGen.create(function);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Function3_1Node.class);
             casts.arg(0).asDoubleVector();
             casts.arg(1).asDoubleVector();
             casts.arg(2).asDoubleVector();
@@ -261,8 +260,8 @@ public final class StatsFunctionsNodes {
             return Function2_1NodeGen.create(function);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Function2_1Node.class);
             casts.arg(0).asDoubleVector();
             casts.arg(1).asDoubleVector();
             casts.arg(2).asLogicalVector().findFirst().map(toBoolean());
@@ -287,8 +286,8 @@ public final class StatsFunctionsNodes {
             return Function2_2NodeGen.create(function);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Function2_2Node.class);
             casts.arg(0).asDoubleVector();
             casts.arg(1).asDoubleVector();
             casts.arg(2).asLogicalVector().findFirst().map(toBoolean());
@@ -308,8 +307,8 @@ public final class StatsFunctionsNodes {
             return ApproxTestNodeGen.create();
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ApproxTest.class);
             casts.arg(2).asIntegerVector().findFirst();
             casts.arg(3).asDoubleVector().findFirst();
         }
@@ -346,8 +345,8 @@ public final class StatsFunctionsNodes {
             return ApproxNodeGen.create();
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Approx.class);
             casts.arg(2).asDoubleVector();
             casts.arg(3).asIntegerVector().findFirst();
             casts.arg(4).asDoubleVector().findFirst();
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/C_ParseRd.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/C_ParseRd.java
index 07a64735ebe6b4b72ad4bdb44296960b1865acf1..915a54f6139f5840e36e127a899765f663abec06 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/C_ParseRd.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/C_ParseRd.java
@@ -30,7 +30,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.ffi.AsIntegerNode;
 import com.oracle.truffle.r.nodes.ffi.AsLogicalNode;
@@ -47,8 +46,8 @@ import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
 public abstract class C_ParseRd extends RExternalBuiltinNode.Arg9 {
     @Child ToolsRFFI.ParseRdNode parseRdNode = RFFIFactory.getRFFI().getToolsRFFI().createParseRdNode();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(C_ParseRd.class);
         /*
          * Most arguments require coercion using, e.g., asLogical; N.B. GNU R doesn't check
          * everything, e.g., srcfile. Since this is "internal" code we do not really expect argument
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java
index 0be43a71887efe09c50a4fc1aa6663f986a67046..9685b25687c58acaaac849aabf0e6e646fc11538 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java
@@ -27,7 +27,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -42,8 +41,8 @@ public abstract class DirChmod extends RExternalBuiltinNode.Arg2 {
     private static final int FILE_MASK = 0644;
     private static final int DIR_MASK = 0755;
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(DirChmod.class);
         casts.arg(0, "dir").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
         casts.arg(1).asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
     }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/Rmd5.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/Rmd5.java
index adb3cbb0305b3fa23c213e1504a4af1e661a9a21..7b9d09c4a88998f7960e151953c037d2432275b1 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/Rmd5.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/Rmd5.java
@@ -33,7 +33,6 @@ import java.security.NoSuchAlgorithmException;
 
 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.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -45,8 +44,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 public abstract class Rmd5 extends RExternalBuiltinNode.Arg1 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Rmd5.class);
         casts.arg(0).defaultError(RError.NO_CALLER, RError.Message.ARG_MUST_BE_CHARACTER, "files").mustBe(stringValue());
     }
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/ToolsText.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/ToolsText.java
index 661cd6bd3bd7d150d6dcf993447dcd2cbb79004b..576ff1bd5571c60a5808cddb9a6da9a002ebe27e 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/ToolsText.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/ToolsText.java
@@ -25,7 +25,6 @@ import java.nio.file.Path;
 
 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.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -37,8 +36,8 @@ public class ToolsText {
 
     public abstract static class DoTabExpand extends RExternalBuiltinNode.Arg2 {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(DoTabExpand.class);
             casts.arg(0, "strings").defaultError(RError.NO_CALLER, RError.Message.MACRO_CAN_BE_APPLIED_TO, "STRING_ELT()", "character vector", typeName()).mustBe(stringValue());
             casts.arg(1, "starts").defaultError(RError.NO_CALLER, RError.Message.MACRO_CAN_BE_APPLIED_TO, "INTEGER()", "integer", typeName()).mustBe(integerValue()).asIntegerVector();
         }
@@ -79,8 +78,8 @@ public class ToolsText {
 
     public abstract static class CodeFilesAppend extends RExternalBuiltinNode.Arg2 {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(CodeFilesAppend.class);
             casts.arg(0, "file1").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
             casts.arg(1, "file2").mustBe(stringValue()).asStringVector();
         }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java
index 3e898dc731637e138cbf18255152c20d5e0dc14b..cb470182d58a282b25717ef630d53db7111478a2 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java
@@ -53,6 +53,10 @@ public final class CountFields extends RExternalBuiltinNode {
 
     }
 
+    static {
+        Casts.noCasts(CountFields.class);
+    }
+
     @TruffleBoundary
     private static Object countFields(RConnection file, char sepChar, String quoteSet, @SuppressWarnings("unused") int nskip, boolean blskip, char comChar) throws IOException {
         LocalData data = new LocalData();
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Crc64.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Crc64.java
index e0427687483512b5ab3882cd3c2c1c0ec52f2181..51eb47a457af6a813af1e9f27691829cd8aad73f 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Crc64.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Crc64.java
@@ -26,15 +26,14 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 
 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.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 public abstract class Crc64 extends RExternalBuiltinNode.Arg1 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Crc64.class);
         casts.arg(0).mustNotBeNull(RError.NO_CALLER,
                         RError.Message.INPUT_MUST_BE_STRING).mustBe(stringValue(), RError.NO_CALLER, RError.Message.INPUT_MUST_BE_STRING);
     }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Download.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Download.java
index b60dbd422ac43df4993cba131a5b5ffc0e212250..00172482920056c2d34e3ed7af95a425f2b768af 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Download.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Download.java
@@ -37,7 +37,6 @@ import java.nio.file.StandardCopyOption;
 
 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.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -48,8 +47,8 @@ import com.oracle.truffle.r.runtime.RError.Message;
  */
 public abstract class Download extends RExternalBuiltinNode.Arg5 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Download.class);
         casts.arg(0).mustBe(stringValue()).asStringVector().mustBe(notEmpty()).shouldBe(singleElement(), Message.ONLY_FIRST_USED).findFirst();
         casts.arg(1).mustBe(stringValue()).asStringVector().mustBe(notEmpty()).shouldBe(singleElement(), Message.ONLY_FIRST_USED).findFirst();
         casts.arg(2).mustBe(logicalValue()).asLogicalVector().mustBe(notEmpty()).shouldBe(singleElement(), Message.ONLY_FIRST_USED).findFirst().map(toBoolean());
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Menu.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Menu.java
index 23ebf09462371c1da3756e3f5957f7fcba12a035..05fca52ffdc56ddf24dba599db1f3502def339bc 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Menu.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Menu.java
@@ -14,7 +14,6 @@ package com.oracle.truffle.r.library.utils;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.runtime.RError;
@@ -26,8 +25,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 public abstract class Menu extends RExternalBuiltinNode.Arg1 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Menu.class);
         casts.arg(0, "choices").mustBe(Predef.stringValue()).asStringVector().mustBe(Predef.notEmpty());
     }
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java
index 4a9ab559d6053b08859c957a1db5df5ac570a498..ac4688363f6c03f7dfced3ce68c6b2889815a200 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java
@@ -40,7 +40,6 @@ import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
 import com.oracle.truffle.api.instrumentation.StandardTags;
 import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.source.Source;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
 import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation;
@@ -81,8 +80,8 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
  */
 public abstract class Rprof extends RExternalBuiltinNode.Arg8 implements RDataFactory.Listener, MemoryCopyTracer.Listener {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Rprof.class);
         casts.arg(0, "filename").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
         casts.arg(1, "append_mode").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
         casts.arg(2, "dinterval").asDoubleVector().findFirst(RRuntime.DOUBLE_NA);
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/TypeConvert.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/TypeConvert.java
index 88a47ede7f726a3ce829f79180b0a544756d68f3..fb7fbf6c6a7507970d79da42414cb223c82c6fc9 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/TypeConvert.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/TypeConvert.java
@@ -40,6 +40,10 @@ public abstract class TypeConvert extends RExternalBuiltinNode.Arg5 {
 
     @Child private SetFixedAttributeNode setLevelsAttrNode = SetFixedAttributeNode.create(RRuntime.LEVELS_ATTR_KEY);
 
+    static {
+        Casts.noCasts(TypeConvert.class);
+    }
+
     private static boolean isNA(String s, RAbstractStringVector naStrings) {
         // naStrings are in addition to NA_character_
         if (RRuntime.isNA(s)) {
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 0198eb0e04f8e0a9b54d20beb668b6a3f7bde66a..40b36e8afd01bb2d92e74b6bda6dbeb65c326d36 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
@@ -26,7 +26,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -48,8 +47,8 @@ public abstract class APerm extends RBuiltinNode {
     private final BranchProfile emptyPermVector = BranchProfile.create();
     private final ConditionProfile mustResize = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(APerm.class);
         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/Abbrev.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Abbrev.java
index 33c348630cebdb9a158e215880926a1f16ac676d..acf3a5b1ccef9d7419ebddf41ed5ae6539117822 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Abbrev.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Abbrev.java
@@ -18,7 +18,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -30,8 +29,8 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public abstract class Abbrev extends RBuiltinNode {
     private final NACheck naCheck = NACheck.create();
 
-    @Override
-    public void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Abbrev.class);
         casts.arg("x").mustBe(stringValue());
         casts.arg("minlength").asIntegerVector().findFirst().notNA();
         casts.arg("use.classes").asLogicalVector().findFirst().notNA().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/All.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/All.java
index 6f117ef49d84ed3c124eeef424b548f20537a0b1..f5ca96b1a705f87d9d39d606ab3a9b0f61a16861 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/All.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/All.java
@@ -33,6 +33,10 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 @RBuiltin(name = "all", kind = PRIMITIVE, parameterNames = {"...", "na.rm"}, dispatch = SUMMARY_GROUP_GENERIC, behavior = PURE)
 public abstract class All extends Quantifier {
 
+    static {
+        new QuantifierCasts(All.class);
+    }
+
     @Override
     protected boolean emptyVectorResult() {
         return true;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AllNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AllNames.java
index 053928da25d4bfc8bdf9cd7855288bc9f79efe1e..ce62baed1abe2db4b930fa56602958929a9556ab 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AllNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AllNames.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.RASTUtils;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -52,8 +51,8 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxVisitor;
 @RBuiltin(name = "all.names", kind = INTERNAL, parameterNames = {"expr", "functions", "max.names", "unique"}, behavior = PURE)
 public abstract class AllNames extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AllNames.class);
         casts.arg("functions").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).notNA(RRuntime.LOGICAL_FALSE);
         casts.arg("max.names").asIntegerVector().findFirst(0).notNA(0);
         casts.arg("unique").asLogicalVector().findFirst(RRuntime.LOGICAL_TRUE).notNA(RRuntime.LOGICAL_TRUE);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Any.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Any.java
index 7cf2116f10e4ea11bd8f28a7e47d51d0e6d35bb4..3cefcf6e0a0f88a8d79ffd714699daa48cd12283 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Any.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Any.java
@@ -27,12 +27,17 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.r.nodes.builtin.base.Quantifier.QuantifierCasts;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "any", kind = PRIMITIVE, parameterNames = {"...", "na.rm"}, dispatch = SUMMARY_GROUP_GENERIC, behavior = PURE)
 public abstract class Any extends Quantifier {
 
+    static {
+        new QuantifierCasts(Any.class);
+    }
+
     @Override
     protected boolean emptyVectorResult() {
         return false;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java
index 57c48da529aacc0ff7572c242cf1506658bf41fb..dc146c10aaf54a033654d50bf5e9e8102579ed36 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.ValueProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.control.RLengthNode;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -56,8 +55,8 @@ public abstract class AnyNA extends RBuiltinNode {
 
     public abstract byte execute(VirtualFrame frame, Object value, boolean recursive);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AnyNA.class);
         casts.arg("recursive").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Arg.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Arg.java
index 0dca5bbfb11818485db259a0242c9a93e83dfe94..130ec5a77e8d0e2344b0ff675af560e2908df99f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Arg.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Arg.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RType;
@@ -42,8 +41,8 @@ public abstract class Arg extends UnaryArithmeticBuiltinNode {
         super(RType.Double, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION, null);
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Arg.class);
         casts.arg("z").mustBe(numericValue().or(complexValue()), RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION);
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java
index c239b07b293abaec17216c177dff74b1cb2e986b..3ea1d01a8f12b4d3a02e4b7a63d878b9f658d953 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,10 @@ public abstract class Args extends RBuiltinNode {
     @Child private GetFunctions.Get getNode;
     @Child private FrameFunctions.ParentFrame parentFrameNode;
 
+    static {
+        Casts.noCasts(Args.class);
+    }
+
     @Specialization
     protected Object args(VirtualFrame frame, RAbstractStringVector funName) {
         if (funName.getLength() == 0) {
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 8b588ea714477bbd07678f0d8b1508e3f64b5b1d..0e7f1daddea24b9076390b40a68317ed7e35f4dd 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
@@ -25,14 +25,12 @@ 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.instanceOf;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notEmpty;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.typeName;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
-import java.util.function.Function;
-
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -46,7 +44,6 @@ import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRawVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
@@ -79,14 +76,9 @@ public abstract class Array extends RBuiltinNode {
         updateDimNames.executeRAbstractContainer(container, o);
     }
 
-    private String argType(Object arg) {
-        return ((RTypedValue) arg).getRType().getName();
-    }
-
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        Function<Object, Object> argType = this::argType;
-        casts.arg("data").defaultError(RError.SHOW_CALLER, RError.Message.MUST_BE_VECTOR_BUT_WAS, "data", argType).mustBe(abstractVectorValue());
+    static {
+        Casts casts = new Casts(Array.class);
+        casts.arg("data").defaultError(RError.SHOW_CALLER, RError.Message.MUST_BE_VECTOR_BUT_WAS, "data", typeName()).mustBe(abstractVectorValue());
         casts.arg("dim").defaultError(RError.SHOW_CALLER, RError.Message.CANNOT_BE_LENGTH, "dims", 0).mustNotBeNull().asIntegerVector().mustBe(notEmpty());
         casts.arg("dimnames").defaultError(RError.SHOW_CALLER, RError.Message.DIMNAMES_LIST).allowNull().mustBe(instanceOf(RList.class));
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCall.java
index cb65b88f22320b3eb45e95941ebca3477833382b..afc469496d2fef4b66feb7ab30da478b5faefde6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCall.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCall.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,6 +52,10 @@ public abstract class AsCall extends RBuiltinNode {
     private final ConditionProfile nullNamesProfile = ConditionProfile.createBinaryProfile();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
+    static {
+        Casts.noCasts(AsCall.class);
+    }
+
     @Specialization
     protected RLanguage asCallFunction(RList x) {
         // TODO error checks
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 3dc2d41575ec88ceaeabf4c51e79bab4a1bf06e2..0c000916060ff4187bd10ca3e9214b106621644f 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
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RDeparse;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -46,8 +45,8 @@ public abstract class AsCharacter extends RBuiltinNode {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AsCharacter.class);
         casts.arg("x").mapIf(instanceOf(RAbstractListVector.class).not(), asStringVector());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacterFactor.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacterFactor.java
index 170e9ec76ac5b8ecb0b5a3575b296d6a5f15e830..a3878fe3db264360b99a8e48baa21b95de4953c4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacterFactor.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacterFactor.java
@@ -49,6 +49,10 @@ public abstract class AsCharacterFactor extends RBuiltinNode {
     @Child CastToVectorNode castToVectorNode = CastToVectorNode.create();
     @Child private GetFixedAttributeNode getLevelsAttrNode = GetFixedAttributeNode.create(RRuntime.LEVELS_ATTR_KEY);
 
+    static {
+        Casts.noCasts(AsCharacterFactor.class);
+    }
+
     @Specialization
     protected RStringVector doAsCharacterFactor(Object x) {
         byte isFactor = (byte) inheritsNode.execute(x, CLASS_FACTOR_VEC, false);
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 513e3e9adbf3d457b0c5297095f127f33cd414d6..468752482966f3f41627408ee460d278d019bf50 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
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RDispatch;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -40,8 +39,8 @@ public abstract class AsComplex extends RBuiltinNode {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AsComplex.class);
         casts.arg("x").asComplexVector();
     }
 
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 88563df392134bdccd3926a4cc0ae110b2c6fc8a..7c65477dadaea01b5be7c7d03bf7f92fbad9f12d 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
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -39,8 +38,8 @@ public abstract class AsDouble extends RBuiltinNode {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AsDouble.class);
         casts.arg("x").asDoubleVector();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java
index d36f0d5089b3d68b0359f70cba925bdb3d72441b..a049ddd75dc54c4781821ef715b66ad4fc06e004 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java
@@ -35,7 +35,6 @@ import com.oracle.truffle.r.nodes.access.AccessArgumentNode;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.WriteVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.FormalArguments;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
@@ -65,8 +64,8 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 @RBuiltin(name = "as.function.default", kind = INTERNAL, parameterNames = {"x", "envir"}, behavior = PURE)
 public abstract class AsFunction extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AsFunction.class);
         casts.arg("x").mustBe(instanceOf(RAbstractListVector.class).or(instanceOf(RExpression.class)), RError.SHOW_CALLER2, RError.Message.TYPE_EXPECTED, RType.List.getName());
         casts.arg("envir").mustBe(instanceOf(REnvironment.class), RError.Message.INVALID_ENVIRONMENT);
     }
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 ab4de27010394358116e9aa1903456810942e668..f7beffc392de4f77b2af3ee0d97f6649594bf5af 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
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -39,8 +38,8 @@ public abstract class AsInteger extends RBuiltinNode {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AsInteger.class);
         casts.arg("x").asIntegerVector();
     }
 
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 41a7bb16748c91fe7b03db6742459f24d2e30a42..5df1046a5c2b07131232094753f0ae1ba5b7792b 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
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -39,8 +38,8 @@ public abstract class AsLogical extends RBuiltinNode {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AsLogical.class);
         casts.arg("x").asLogicalVector();
     }
 
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 dafd3a6f8a5ecd8de9ec560f43221edabc0d4b49..cd935a7b146abb247afba1ce5a7ac40d0e740923 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -39,8 +38,8 @@ public abstract class AsRaw extends RBuiltinNode {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AsRaw.class);
         casts.arg("x").allowNull().asRawVector();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
index 3add337eeddb6b8c2ec068284a7ee9ed4014c114..facf4b7d25493acf40217c6a9cf88bf2e047068a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
@@ -37,7 +37,6 @@ import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.AsVectorNodeGen.AsVectorInternalNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.AsVectorNodeGen.AsVectorInternalNodeGen.CastPairListNodeGen;
@@ -83,8 +82,8 @@ public abstract class AsVector extends RBuiltinNode {
 
     private final ConditionProfile hasClassProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AsVector.class);
         casts.arg("mode").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
     }
 
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 658e91d839ae71f6f2fee68f0009df72913f1ff8..9b191ab4b93b25fb0aafd0c06591117604ba9b67 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
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.LoopNode;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -91,8 +90,8 @@ public abstract class Assign extends RBuiltinNode {
         }
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Assign.class);
         casts.arg("x").asStringVector().shouldBe(singleElement(), RError.Message.ONLY_FIRST_VARIABLE_NAME).findFirst(RError.Message.INVALID_FIRST_ARGUMENT);
 
         casts.arg("envir").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(REnvironment.class, RError.Message.INVALID_ARGUMENT, "envir");
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 b9103fc9e473631071871f388771dbeda2e494e9..f1ef8beb37181a987574a97dd3a33f1608e1349f 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
@@ -31,7 +31,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -49,8 +48,8 @@ public class AttachFunctions {
     @RBuiltin(name = "attach", visibility = OFF, kind = INTERNAL, parameterNames = {"what", "pos", "name"}, behavior = COMPLEX)
     public abstract static class Attach extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Attach.class);
             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());
@@ -106,8 +105,8 @@ public class AttachFunctions {
     @RBuiltin(name = "detach", visibility = OFF, kind = INTERNAL, parameterNames = {"pos"}, behavior = COMPLEX)
     public abstract static class Detach extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Detach.class);
             casts.arg("pos").mustBe(numericValue(), Message.MUST_BE_INTEGER, "pos").asIntegerVector();
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java
index 0329bf95e8ab9c10a0f8684e6eadb19e24095382..530f77eb8e85431d5f057eaf5ae85b75bcdbdd36 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.GetAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.IterableAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetRowNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.UpdateAttr.InternStringNode;
 import com.oracle.truffle.r.nodes.builtin.base.UpdateAttrNodeGen.InternStringNodeGen;
@@ -74,8 +73,8 @@ public abstract class Attr extends RBuiltinNode {
         return new Object[]{RMissing.instance, RMissing.instance, RRuntime.asLogical(false)};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Attr.class);
         // Note: checking RAttributable.class does not work for scalars
         // casts.arg("x").mustBe(RAttributable.class, Message.UNIMPLEMENTED_ARGUMENT_TYPE);
         casts.arg("which").mustBe(stringValue(), Message.MUST_BE_CHARACTER, "which").asStringVector().mustBe(singleElement(), RError.Message.EXACTLY_ONE_WHICH).findFirst();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attributes.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attributes.java
index 31586b70dfd4794b64d3ff8f98dfcba869811b6f..3c751dc9906fae8a7383ce2d6b64fc22af414917 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attributes.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attributes.java
@@ -56,6 +56,10 @@ public abstract class Attributes extends RBuiltinNode {
     @Child private ArrayAttributeNode arrayAttrAccess = ArrayAttributeNode.create();
     @Child private SetNamesAttributeNode setNamesNode = SetNamesAttributeNode.create();
 
+    static {
+        Casts.noCasts(Attributes.class);
+    }
+
     @Specialization
     protected Object attributesNull(RAbstractContainer container,
                     @Cached("createBinaryProfile()") ConditionProfile hasAttributesProfile) {
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 576d36eda1da32515b1562e92e8ab3cef8bb72f1..e883fc44c570cd9ca10913bff2b7624ae5095602 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
@@ -31,7 +31,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.NodeChild;
 import com.oracle.truffle.api.dsl.NodeChildren;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.BaseGammaFunctionsFactory.DpsiFnCalcNodeGen;
 import com.oracle.truffle.r.runtime.RError;
@@ -73,8 +72,8 @@ public class BaseGammaFunctions {
 
         private final NACheck naValCheck = NACheck.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Lgamma.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue()).asDoubleVector();
         }
 
@@ -116,8 +115,8 @@ public class BaseGammaFunctions {
             return dpsiFnCalc.executeDouble(x, n, kode, ans);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(DiGamma.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue()).asDoubleVector();
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bincode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bincode.java
index feb0ae5f278c8bfaea909c862ae52cafb7910c97..1c9c02253cef6f4fe4698f6ebc41ffec753b712b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bincode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bincode.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -17,7 +17,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -33,8 +32,8 @@ public abstract class Bincode extends RBuiltinNode {
     private final BranchProfile errorProfile = BranchProfile.create();
     private final NACheck naCheck = NACheck.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Bincode.class);
         casts.arg("x").asDoubleVector();
 
         casts.arg("breaks").asDoubleVector();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java
index b01b00dea10445156396ab78d186a30532d1fe24..13da55b7f959329fcc8f821facf284c7e09b46b0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java
@@ -41,7 +41,6 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNa
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNodeGen;
@@ -525,18 +524,30 @@ public abstract class Bind extends RBaseNode {
         return result;
     }
 
+    @SuppressWarnings("unused")
     @RBuiltin(name = "cbind", kind = INTERNAL, parameterNames = {"deparse.level", "..."}, behavior = COMPLEX)
     public abstract static class CbindInternal extends AbstractBind {
         public CbindInternal() {
             super(BindType.cbind);
         }
+
+        static {
+            new BindCasts(CbindInternal.class);
+        }
+
     }
 
+    @SuppressWarnings("unused")
     @RBuiltin(name = "rbind", kind = INTERNAL, parameterNames = {"deparse.level", "..."}, behavior = COMPLEX)
     public abstract static class RbindInternal extends AbstractBind {
         public RbindInternal() {
             super(BindType.rbind);
         }
+
+        static {
+            new BindCasts(RbindInternal.class);
+        }
+
     }
 
     protected abstract static class AbstractBind extends RBuiltinNode {
@@ -557,9 +568,11 @@ public abstract class Bind extends RBaseNode {
             this.type = type;
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("deparse.level").asIntegerVector().findFirst(0);
+        static final class BindCasts extends Casts {
+            BindCasts(Class<? extends AbstractBind> extCls) {
+                super(extCls);
+                casts.arg("deparse.level").asIntegerVector().findFirst(0);
+            }
         }
 
         @Specialization
@@ -614,6 +627,7 @@ public abstract class Bind extends RBaseNode {
             }
             return result != null ? result.function : null;
         }
+
     }
 
     public RVector<?> genericRBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, RVector<?> result, int[] resultDimensions, int[] firstDims, boolean rowsAndColumnsNotEqual,
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 ae96659c840be4306e46f65b4fa4b2e01beabf9e..9fe775ec76542ac41c9933fc3e37c2bc649c464e 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
@@ -19,15 +19,13 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.shouldBe;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.typeName;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
-import java.util.function.Function;
-
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNodeGen;
@@ -137,19 +135,15 @@ public class BitwiseFunctions {
             }
             return RDataFactory.createIntVector(na, RDataFactory.INCOMPLETE_VECTOR);
         }
-
-        protected Function<Object, String> getArgType() {
-            return x -> typeofA.execute(x).getName();
-        }
     }
 
     @RBuiltin(name = "bitwiseAnd", kind = INTERNAL, parameterNames = {"a", "b"}, behavior = PURE)
     public abstract static class BitwiseAnd extends BasicBitwise {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            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();
+        static {
+            Casts casts = new Casts(BitwiseAnd.class);
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.AND.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+            casts.arg("b").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.AND.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
         }
 
         @Specialization
@@ -167,10 +161,10 @@ public class BitwiseFunctions {
     @RBuiltin(name = "bitwiseOr", kind = INTERNAL, parameterNames = {"a", "b"}, behavior = PURE)
     public abstract static class BitwiseOr extends BasicBitwise {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            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();
+        static {
+            Casts casts = new Casts(BitwiseOr.class);
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.OR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+            casts.arg("b").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.OR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
         }
 
         @Specialization
@@ -188,10 +182,10 @@ public class BitwiseFunctions {
     @RBuiltin(name = "bitwiseXor", kind = INTERNAL, parameterNames = {"a", "b"}, behavior = PURE)
     public abstract static class BitwiseXor extends BasicBitwise {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            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();
+        static {
+            Casts casts = new Casts(BitwiseXor.class);
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.XOR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+            casts.arg("b").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.XOR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
         }
 
         @Specialization
@@ -209,9 +203,9 @@ public class BitwiseFunctions {
     @RBuiltin(name = "bitwiseShiftR", kind = INTERNAL, parameterNames = {"a", "n"}, behavior = PURE)
     public abstract static class BitwiseShiftR extends BasicBitwise {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.SHIFTR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+        static {
+            Casts casts = new Casts(BitwiseShiftR.class);
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.SHIFTR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
             casts.arg("n").mapIf(stringValue(), asStringVector(), asIntegerVector());
         }
 
@@ -236,9 +230,9 @@ public class BitwiseFunctions {
     @RBuiltin(name = "bitwiseShiftL", kind = INTERNAL, parameterNames = {"a", "n"}, behavior = PURE)
     public abstract static class BitwiseShiftL extends BasicBitwise {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("a").defaultError(RError.ROOTNODE, RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.SHIFTL.name).mustBe(
+        static {
+            Casts casts = new Casts(BitwiseShiftL.class);
+            casts.arg("a").defaultError(RError.ROOTNODE, RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.SHIFTL.name).mustBe(
                             doubleValue().or(integerValue())).asIntegerVector();
             casts.arg("n").allowNull().mapIf(stringValue(), chain(asStringVector()).with(shouldBe(anyValue().not(), RError.SHOW_CALLER, RError.Message.NA_INTRODUCED_COERCION)).end(),
                             asIntegerVector());
@@ -265,10 +259,12 @@ public class BitwiseFunctions {
     @RBuiltin(name = "bitwiseNot", kind = INTERNAL, parameterNames = {"a"}, behavior = PURE)
     public abstract static class BitwiseNot extends BasicBitwise {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.NOT.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
-        }
+        // @formatter:off
+    static {
+        Casts casts = new Casts(BitwiseNot.class);
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.NOT.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+    }
+        //@formatter:on
 
         @Specialization
         protected Object bitwNot(RAbstractIntVector a) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Body.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Body.java
index e852f86379df5b2dbd48b70d9c83c6c3dad45227..53812789a2944309cbbdf2ef82272156fee822a9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Body.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Body.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,10 @@ import com.oracle.truffle.r.runtime.data.RNull;
 @RBuiltin(name = "body", kind = INTERNAL, parameterNames = {"fun"}, behavior = PURE)
 public abstract class Body extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(Body.class);
+    }
+
     @Specialization
     protected Object doBody(RFunction fun) {
         FunctionDefinitionNode fdn = (FunctionDefinitionNode) fun.getRootNode();
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 b84302c5ffcc52557427647dab89c8ac5402c4e5..2e2226c33973bc0588b6fa9d509179b91bcd9fa8 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
@@ -34,7 +34,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.helpers.BrowserInteractNode;
 import com.oracle.truffle.r.nodes.builtin.helpers.BrowserInteractNodeGen;
@@ -61,8 +60,8 @@ public class BrowserFunctions {
             return new Object[]{"", RNull.instance, RRuntime.LOGICAL_TRUE, 0};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(BrowserNode.class);
             // TODO: add support for conditions conditions
             casts.arg("condition").mustBe(nullValue(), RError.Message.GENERIC, "Only NULL conditions currently supported in browser");
             casts.arg("expr").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
@@ -102,8 +101,8 @@ public class BrowserFunctions {
 
     private abstract static class RetrieveAdapter extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(RetrieveAdapter.class);
             casts.arg("n").asIntegerVector().findFirst(0).mustBe(gt(0), Message.POSITIVE_CONTEXTS);
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java
index 3c0d9280a583a1773f28b7d90320efd0ec075ff8..8680eccad330fbf154b34fd6b2760027bd4c48d5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.library.utils.Crc64;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -39,8 +38,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "crc64", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
 public abstract class CRC64 extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CRC64.class);
         casts.arg("x").defaultError(RError.NO_CALLER, Message.INPUT_MUST_BE_STRING).mustBe(stringValue());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CacheClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CacheClass.java
index 9c0d5bd0f09e1fcc36073b2b43ea76ef84a00536..d95ff7128f3770fff7879ddaf065c0641d266c2f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CacheClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CacheClass.java
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -18,7 +18,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -28,8 +27,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = ".cache_class", kind = PRIMITIVE, parameterNames = {"class", "extends"}, behavior = COMPLEX)
 public abstract class CacheClass extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CacheClass.class);
         casts.arg("class").defaultError(RError.Message.GENERIC, "invalid class argument to internal .class_cache").mustBe(stringValue()).asStringVector().findFirst();
         // apparently, "extends" does not have to be a string vector (GNU R will not signal this
         // error) - but it does not seem to make much sense and it's doubtful if it's worth
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java
index b219b18a59b1eae4700ad3e57955c31ca3ae14ab..ed84a24405e3deb35548b798fb1de41f4fb6f895 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RError;
@@ -64,8 +63,8 @@ public abstract class Call extends RBuiltinNode {
         return new Object[]{RMissing.instance, RArgsValuesAndNames.EMPTY};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Call.class);
         casts.arg("").mustBe(stringValue(), RError.Message.FIRST_ARG_MUST_BE_STRING).asStringVector().findFirst();
     }
 
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 f42bc2c3c55879ee53857a239cde26a8a31d9605..d1e14444e7d9e2e0985a955a947e8b3622d5c25b 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,6 @@ import java.util.ArrayList;
 import com.oracle.truffle.api.CompilerDirectives;
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.ToStringNode;
 import com.oracle.truffle.r.nodes.unary.ToStringNodeGen;
@@ -77,8 +76,8 @@ public abstract class Cat extends RBuiltinNode {
         }
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Cat.class);
         casts.arg("sep").mustBe(stringValue(), RError.Message.INVALID_SEP);
 
         casts.arg("file").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
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 b8cf2bdb964b9148910210cbebf9a314c7be6118..97a39652446ab3a30f9a514bf3c94bbe1ee7fb0e 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
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RType;
@@ -47,16 +46,10 @@ public abstract class Ceiling extends UnaryArithmeticBuiltinNode {
         super(RType.Double, RError.Message.NON_NUMERIC_MATH, null);
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        //@formatter:off
-        casts.arg("x").
-            defaultError(this, RError.Message.NON_NUMERIC_MATH).
-            mustNotBeNull().
-            mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).
-            mustBe(numericValue()).
-            asDoubleVector(true, true, true);
-        //@formatter:on
+    static {
+        Casts casts = new Casts(Ceiling.class);
+        casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustNotBeNull().mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue()).asDoubleVector(true,
+                        true, true);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CharMatch.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CharMatch.java
index 335418deeb7d23845198344b06c82f5850e81256..86c6b72e20b2213e78770ee652c63338a694da7f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CharMatch.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CharMatch.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -15,7 +15,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -28,8 +27,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "charmatch", kind = INTERNAL, parameterNames = {"x", "table", "noMatch"}, behavior = PURE)
 public abstract class CharMatch extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CharMatch.class);
         casts.arg("x").mustBe(stringValue(), RError.NO_CALLER, Message.ARG_IS_NOT_OF_MODE, "character");
         casts.arg("table").mustBe(stringValue(), RError.NO_CALLER, Message.ARG_IS_NOT_OF_MODE, "character");
         casts.arg("noMatch").asIntegerVector().findFirst(RRuntime.INT_NA);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ChooseBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ChooseBuiltin.java
index 7a63eaf5b95e3e15a260d7335ef085a125788fd2..c72287f73e7e01b29521610aaaefac601bf29f24 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ChooseBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ChooseBuiltin.java
@@ -32,7 +32,6 @@ import java.util.function.IntToDoubleFunction;
 import java.util.function.IntUnaryOperator;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -53,8 +52,8 @@ public abstract class ChooseBuiltin extends RBuiltinNode {
 
     private final NACheck na = NACheck.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(ChooseBuiltin.class);
         casts.arg("n").mustBe(numericValue(), RError.SHOW_CALLER, Message.NON_NUMERIC_MATH).mapIf(logicalValue(), asIntegerVector());
         casts.arg("k").mustBe(numericValue(), RError.SHOW_CALLER, Message.NON_NUMERIC_MATH).mapIf(logicalValue(), asIntegerVector());
     }
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 99cca9a9198ce462fbd6bec2319020513232b39e..242bce76a30f0d1b7d53f5ce97e6ae316a2e6b92 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
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import java.util.Arrays;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -41,8 +40,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 @RBuiltin(name = "col", kind = INTERNAL, parameterNames = {"dims"}, behavior = PURE)
 public abstract class Col extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Col.class);
         casts.arg("dims").defaultError(RError.SHOW_CALLER, RError.Message.MATRIX_LIKE_REQUIRED, "col").mustBe(integerValue()).asIntegerVector().mustBe(size(2));
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColMeans.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColMeans.java
index 744d723842fcdc2439c30c33c08afc7157a10136..121a78c81fc458de9db3c1977fc98fcbc7087782 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColMeans.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColMeans.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -24,11 +24,16 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 
 //Implements .colMeans
+@SuppressWarnings("unused")
 @RBuiltin(name = "colMeans", kind = INTERNAL, parameterNames = {"X", "m", "n", "na.rm"}, behavior = PURE)
 public abstract class ColMeans extends ColSumsBase {
 
     @Child private BinaryArithmetic add = BinaryArithmetic.ADD.createOperation();
 
+    static {
+        new ColSumsCasts(ColMeans.class);
+    }
+
     @Specialization(guards = "!naRm")
     protected RDoubleVector colMeansNaRmFalse(RAbstractDoubleVector x, int rowNum, int colNum, @SuppressWarnings("unused") boolean naRm) {
         checkVectorLength(x, rowNum, colNum);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSums.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSums.java
index bafef83f8fa17d1eb8064ef03f46f05de8534d92..7dce23f2daf123bd23abfe6ef02326ed5c06bcf4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSums.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSums.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 
+@SuppressWarnings("unused")
 @RBuiltin(name = "colSums", kind = INTERNAL, parameterNames = {"X", "m", "n", "na.rm"}, behavior = PURE)
 public abstract class ColSums extends ColSumsBase {
 
@@ -45,6 +46,10 @@ public abstract class ColSums extends ColSumsBase {
     private final ConditionProfile removeNA = ConditionProfile.createBinaryProfile();
     private final ValueProfile concreteVectorProfile = ValueProfile.createClassProfile();
 
+    static {
+        new ColSumsCasts(ColSums.class);
+    }
+
     @Specialization
     protected RDoubleVector colSums(RAbstractDoubleVector x, int rowNum, int colNum, boolean rnaParam) {
         checkVectorLength(x, rowNum, colNum);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSumsBase.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSumsBase.java
index 86d65c04da3c9a1f480b306ad8d39fe34c141687..1f14bc7a118e1d09332675b33a4ec6add0199384 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSumsBase.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSumsBase.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.RError.Message.INVALID_ARGUMENT;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -47,12 +46,14 @@ public abstract class ColSumsBase extends RBuiltinNode {
     protected final NACheck na = NACheck.create();
     private final ConditionProfile vectorLengthProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected final void createCasts(CastBuilder casts) {
-        casts.arg("X").mustBe(numericValue(), RError.SHOW_CALLER, RError.Message.X_NUMERIC);
-        casts.arg("m").defaultError(RError.SHOW_CALLER, INVALID_ARGUMENT, "n").asIntegerVector().findFirst().notNA(RError.NO_CALLER, RError.Message.VECTOR_SIZE_NA);
-        casts.arg("n").defaultError(RError.SHOW_CALLER, INVALID_ARGUMENT, "p").asIntegerVector().findFirst().notNA(RError.NO_CALLER, RError.Message.VECTOR_SIZE_NA);
-        casts.arg("na.rm").asLogicalVector().findFirst().notNA().map(toBoolean());
+    static final class ColSumsCasts extends Casts {
+        ColSumsCasts(Class<? extends ColSumsBase> extCls) {
+            super(extCls);
+            casts.arg("X").mustBe(numericValue(), RError.SHOW_CALLER, RError.Message.X_NUMERIC);
+            casts.arg("m").defaultError(RError.SHOW_CALLER, INVALID_ARGUMENT, "n").asIntegerVector().findFirst().notNA(RError.NO_CALLER, RError.Message.VECTOR_SIZE_NA);
+            casts.arg("n").defaultError(RError.SHOW_CALLER, INVALID_ARGUMENT, "p").asIntegerVector().findFirst().notNA(RError.NO_CALLER, RError.Message.VECTOR_SIZE_NA);
+            casts.arg("na.rm").asLogicalVector().findFirst().notNA().map(toBoolean());
+        }
     }
 
     protected final void checkVectorLength(RAbstractVector x, int rowNum, int colNum) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Colon.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Colon.java
index 0be1946f7546c82aa894ae2d98332260a1c1d311..9fa28b86e33fd778f08c9a0d7512b16ddec949b9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Colon.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Colon.java
@@ -58,6 +58,10 @@ public abstract class Colon extends RBuiltinNode {
     @Child private ColonCastNode rightCast = ColonCastNodeGen.create();
     @Child private ColonInternal internal = ColonInternalNodeGen.create();
 
+    static {
+        Casts.noCasts(Colon.class);
+    }
+
     @Specialization
     protected RSequence colon(Object left, Object right) {
         return internal.execute(leftCast.execute(left), rightCast.execute(right));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
index 56d47d9a6f17673d8dcf00c57c7acd00ebc495bd..1e068b47c7802987bc7b3c80b8362fc3a6d8819c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
@@ -49,7 +49,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.CombineNodeGen.CombineInputCastNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastComplexNodeGen;
@@ -104,8 +103,8 @@ public abstract class Combine extends RBuiltinNode {
     private final ConditionProfile hasNewNamesProfile = ConditionProfile.createBinaryProfile();
     @CompilationFinal private final ValueProfile[] argProfiles = new ValueProfile[MAX_PROFILES];
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Combine.class);
         casts.arg("recursive").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CompileFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CompileFunctions.java
index fd951173e3a2144253f774b7499ef39acffe8451..7fb2b3ce4d4c9c558cda43fd5bff4ff849c9a436 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CompileFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CompileFunctions.java
@@ -26,7 +26,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
@@ -38,8 +37,8 @@ public class CompileFunctions {
     @RBuiltin(name = "compilePKGS", kind = INTERNAL, parameterNames = "enable", behavior = PURE)
     public abstract static class CompilePKGS extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(CompilePKGS.class);
             casts.arg("enable").asIntegerVector().findFirst(0);
         }
 
@@ -51,8 +50,9 @@ public class CompileFunctions {
 
     @RBuiltin(name = "enableJIT", kind = INTERNAL, parameterNames = "level", behavior = PURE)
     public abstract static class EnableJIT extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(EnableJIT.class);
             casts.arg("level").asIntegerVector().findFirst(0);
         }
 
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 a18522b37689d92276fc10e58cf79fae4ef4fcd0..f8826494d7df98c923ecb41e5cdad4ec5a076837 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -42,8 +41,8 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 @RBuiltin(name = "complex", kind = INTERNAL, parameterNames = {"length.out", "real", "imaginary"}, behavior = PURE)
 public abstract class Complex extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Complex.class);
         casts.arg("length.out").asIntegerVector().findFirst(Message.INVALID_LENGTH);
         casts.arg("real").mapNull(emptyDoubleVector()).asDoubleVector();
         casts.arg("imaginary").mapNull(emptyDoubleVector()).asDoubleVector();
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 d9d86038cfa8c8d85b183a42bf9458079eb4bac6..00bae3fd40b5fedb794b844b998d534756cfb087 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
@@ -28,6 +28,8 @@ import com.oracle.truffle.api.frame.FrameSlotTypeException;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
+import com.oracle.truffle.r.nodes.builtin.base.foreign.CallAndExternalFunctions.DotExternal2;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -58,8 +60,9 @@ public class ConditionFunctions {
 
     @RBuiltin(name = ".addCondHands", visibility = OFF, kind = INTERNAL, parameterNames = {"classes", "handlers", "parentenv", "target", "calling"}, behavior = COMPLEX)
     public abstract static class AddCondHands extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(AddCondHands.class);
             casts.arg("classes").allowNull().mustBe(stringValue()).asStringVector();
             casts.arg("handlers").allowNull().mustBe(instanceOf(RList.class));
             casts.arg("calling").asLogicalVector().findFirst();
@@ -116,15 +119,16 @@ public class ConditionFunctions {
             }
         }
 
-        protected void restart(CastBuilder casts) {
+        protected static void restart(Casts casts) {
             casts.arg("restart").mustBe(instanceOf(RList.class), RError.Message.BAD_RESTART);
         }
     }
 
     @RBuiltin(name = ".addRestart", kind = INTERNAL, parameterNames = "restart", behavior = COMPLEX)
     public abstract static class AddRestart extends RestartAdapter {
-        @Override
-        public void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(AddRestart.class);
             restart(casts);
         }
 
@@ -150,8 +154,9 @@ public class ConditionFunctions {
 
     @RBuiltin(name = ".getRestart", kind = INTERNAL, parameterNames = "restart", behavior = COMPLEX)
     public abstract static class GetRestart extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(GetRestart.class);
             casts.arg("restart").asIntegerVector().findFirst();
         }
 
@@ -164,8 +169,9 @@ public class ConditionFunctions {
 
     @RBuiltin(name = ".invokeRestart", kind = INTERNAL, parameterNames = {"restart", "args"}, behavior = COMPLEX)
     public abstract static class InvokeRestart extends RestartAdapter {
-        @Override
-        public void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(InvokeRestart.class);
             restart(casts);
         }
 
@@ -183,6 +189,11 @@ public class ConditionFunctions {
 
     @RBuiltin(name = ".signalCondition", kind = INTERNAL, parameterNames = {"condition", "msg", "call"}, behavior = COMPLEX)
     public abstract static class SignalCondition extends RBuiltinNode {
+
+        static {
+            Casts.noCasts(SignalCondition.class);
+        }
+
         @Specialization
         protected RNull signalCondition(RList condition, RAbstractStringVector msg, Object call) {
             RErrorHandling.signalCondition(condition, msg.getDataAt(0), call);
@@ -200,8 +211,9 @@ public class ConditionFunctions {
 
     @RBuiltin(name = "seterrmessage", visibility = OFF, kind = INTERNAL, parameterNames = "msg", behavior = COMPLEX)
     public abstract static class Seterrmessage extends RBuiltinNode {
-        @Override
-        public void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(Seterrmessage.class);
             casts.arg("msg").defaultError(RError.Message.ERR_MSG_MUST_BE_STRING).mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
         }
 
@@ -214,8 +226,9 @@ public class ConditionFunctions {
 
     @RBuiltin(name = ".dfltWarn", kind = INTERNAL, parameterNames = {"message", "call"}, behavior = COMPLEX)
     public abstract static class DfltWarn extends RBuiltinNode {
-        @Override
-        public void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(DfltWarn.class);
             casts.arg("message").defaultError(RError.Message.ERR_MSG_BAD).mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
         }
 
@@ -228,8 +241,9 @@ public class ConditionFunctions {
 
     @RBuiltin(name = ".dfltStop", kind = INTERNAL, parameterNames = {"message", "call"}, behavior = COMPLEX)
     public abstract static class DfltStop extends RBuiltinNode {
-        @Override
-        public void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(DfltStop.class);
             casts.arg("message").defaultError(RError.Message.ERR_MSG_BAD).mustBe(stringValue()).asStringVector().mustBe(size(1)).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 ae401acf12b4fc93ff770c983fb29132ead16d72..579c88b0eaf9f2a68df075708607cfc4c5dfb0af 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
@@ -57,7 +57,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.dsl.TypeSystemReference;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.ConnectionFunctionsFactory.WriteDataNodeGen;
 import com.oracle.truffle.r.nodes.builtin.casts.fluent.HeadPhaseBuilder;
@@ -134,52 +134,52 @@ public abstract class ConnectionFunctions {
         }
     }
 
-    public static final class Casts {
-        private static void description(CastBuilder casts) {
+    public static final class CastsHelper {
+        private static void description(Casts casts) {
             casts.arg("description").mustBe(stringValue()).asStringVector().shouldBe(singleElement(), RError.Message.ARGUMENT_ONLY_FIRST_1, "description").findFirst().notNA();
         }
 
-        private static HeadPhaseBuilder<String> open(CastBuilder casts) {
+        private static HeadPhaseBuilder<String> open(Casts casts) {
             return casts.arg("open").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst().notNA();
         }
 
-        private static void encoding(CastBuilder casts) {
+        private static void encoding(Casts casts) {
             casts.arg("encoding").asStringVector().mustBe(singleElement()).findFirst();
         }
 
-        private static void raw(CastBuilder casts) {
+        private static void raw(Casts casts) {
             casts.arg("raw").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
-        private static void blocking(CastBuilder casts) {
+        private static void blocking(Casts casts) {
             casts.arg("blocking").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
-        public static void connection(CastBuilder casts) {
+        public static void connection(Casts casts) {
             casts.arg("con").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
         }
 
-        private static void nchars(CastBuilder casts) {
+        private static void nchars(Casts casts) {
             casts.arg("nchars").asIntegerVector().mustBe(notEmpty());
         }
 
-        private static void useBytes(CastBuilder casts) {
+        private static void useBytes(Casts casts) {
             casts.arg("useBytes").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
-        private static void n(CastBuilder casts) {
+        private static void n(Casts casts) {
             casts.arg("n").asIntegerVector().findFirst().mustBe(gte(0));
         }
 
-        private static void size(CastBuilder casts) {
+        private static void size(Casts casts) {
             casts.arg("size").asIntegerVector().findFirst();
         }
 
-        private static void swap(CastBuilder casts) {
+        private static void swap(Casts casts) {
             casts.arg("swap").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
-        private static void method(CastBuilder casts) {
+        private static void method(Casts casts) {
             casts.arg("method").asStringVector().findFirst();
         }
     }
@@ -187,14 +187,14 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "file", kind = INTERNAL, parameterNames = {"description", "open", "blocking", "encoding", "method", "raw"}, behavior = IO)
     public abstract static class File extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.description(casts);
-            Casts.open(casts);
+        static {
+            Casts casts = new Casts(File.class);
+            CastsHelper.description(casts);
+            CastsHelper.open(casts);
             casts.arg("blocking").asLogicalVector().findFirst().mustBe(logicalTrue(), RError.Message.NYI, "non-blocking mode not supported").map(toBoolean());
-            Casts.encoding(casts);
-            Casts.method(casts);
-            Casts.raw(casts);
+            CastsHelper.encoding(casts);
+            CastsHelper.method(casts);
+            CastsHelper.raw(casts);
         }
 
         @Specialization
@@ -236,12 +236,14 @@ public abstract class ConnectionFunctions {
             this.cType = cType;
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.description(casts);
-            Casts.open(casts);
-            Casts.encoding(casts);
-            casts.arg("compression").asIntegerVector().findFirst().notNA().mustBe(gte(cType == RCompression.Type.XZ ? -9 : 0).and(lte(9)));
+        static final class ZZCasts extends Casts {
+            protected ZZCasts(Class<? extends ZZFileAdapter> extCls, RCompression.Type cType) {
+                super(extCls);
+                CastsHelper.description(this);
+                CastsHelper.open(this);
+                CastsHelper.encoding(this);
+                casts.arg("compression").asIntegerVector().findFirst().notNA().mustBe(gte(cType == RCompression.Type.XZ ? -9 : 0).and(lte(9)));
+            }
         }
 
         @Specialization
@@ -260,37 +262,56 @@ public abstract class ConnectionFunctions {
         }
     }
 
+    @SuppressWarnings("unused")
     @RBuiltin(name = "gzfile", kind = INTERNAL, parameterNames = {"description", "open", "encoding", "compression"}, behavior = IO)
     public abstract static class GZFile extends ZZFileAdapter {
         protected GZFile() {
             super(RCompression.Type.GZIP);
         }
+
+        static {
+            new ZZCasts(GZFile.class, RCompression.Type.GZIP);
+        }
+
     }
 
+    @SuppressWarnings("unused")
     @RBuiltin(name = "bzfile", kind = INTERNAL, parameterNames = {"description", "open", "encoding", "compression"}, behavior = IO)
     public abstract static class BZFile extends ZZFileAdapter {
         protected BZFile() {
             super(RCompression.Type.BZIP2);
         }
+
+        static {
+            new ZZCasts(BZFile.class, RCompression.Type.BZIP2);
+        }
+
     }
 
+    @SuppressWarnings("unused")
     @RBuiltin(name = "xzfile", kind = INTERNAL, parameterNames = {"description", "open", "encoding", "compression"}, behavior = IO)
     public abstract static class XZFile extends ZZFileAdapter {
         protected XZFile() {
             super(RCompression.Type.XZ);
         }
+
+        static {
+            new ZZCasts(XZFile.class, RCompression.Type.XZ);
+        }
+
     }
 
     @RBuiltin(name = "textConnection", kind = INTERNAL, parameterNames = {"description", "text", "open", "env", "encoding"}, behavior = IO)
     public abstract static class TextConnection extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.description(casts);
+
+        static {
+            Casts casts = new Casts(TextConnection.class);
+            CastsHelper.description(casts);
             // 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").allowNull().mustBe(stringValue());
-            Casts.open(casts).mustBe(equalTo("").or(equalTo("r").or(equalTo("w").or(equalTo("a")))), RError.Message.UNSUPPORTED_MODE);
+            CastsHelper.open(casts).mustBe(equalTo("").or(equalTo("r").or(equalTo("w").or(equalTo("a")))), RError.Message.UNSUPPORTED_MODE);
             casts.arg("env").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
             casts.arg("encoding").asIntegerVector().findFirst().notNA();
         }
@@ -330,8 +351,9 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "textConnectionValue", kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
     public abstract static class TextConnectionValue extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(TextConnectionValue.class);
             casts.arg("con").defaultError(Message.NOT_A_TEXT_CONNECTION).mustBe(integerValue()).asIntegerVector().findFirst();
         }
 
@@ -350,13 +372,13 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "socketConnection", kind = INTERNAL, parameterNames = {"host", "port", "server", "blocking", "open", "encoding", "timeout"}, behavior = IO)
     public abstract static class SocketConnection extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SocketConnection.class);
             casts.arg("host").mustBe(stringValue()).asStringVector().findFirst();
             casts.arg("port").asIntegerVector().findFirst().notNA().mustBe(gte(0));
             casts.arg("server").asLogicalVector().findFirst().notNA().map(toBoolean());
-            Casts.open(casts);
-            Casts.blocking(casts);
+            CastsHelper.open(casts);
+            CastsHelper.blocking(casts);
             casts.arg("timeout").asIntegerVector().findFirst();
         }
 
@@ -379,13 +401,13 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "url", kind = INTERNAL, parameterNames = {"description", "open", "blocking", "encoding", "method"}, behavior = IO)
     public abstract static class URLConnection extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.description(casts);
-            Casts.open(casts);
-            Casts.blocking(casts);
-            Casts.encoding(casts);
-            Casts.method(casts);
+        static {
+            Casts casts = new Casts(URLConnection.class);
+            CastsHelper.description(casts);
+            CastsHelper.open(casts);
+            CastsHelper.blocking(casts);
+            CastsHelper.encoding(casts);
+            CastsHelper.method(casts);
         }
 
         @Specialization
@@ -407,8 +429,8 @@ public abstract class ConnectionFunctions {
         private static final RStringVector NAMES = RDataFactory.createStringVector(new String[]{"description", "class", "mode", "text", "opened", "can read", "can write"},
                         RDataFactory.COMPLETE_VECTOR);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Summary.class);
             casts.arg("object").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
         }
 
@@ -431,11 +453,11 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "open", visibility = OFF, kind = INTERNAL, parameterNames = {"con", "open", "blocking"}, behavior = IO)
     public abstract static class Open extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
-            Casts.open(casts);
-            Casts.blocking(casts);
+        static {
+            Casts casts = new Casts(Open.class);
+            CastsHelper.connection(casts);
+            CastsHelper.open(casts);
+            CastsHelper.blocking(casts);
         }
 
         @Specialization
@@ -460,9 +482,10 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "isOpen", kind = INTERNAL, parameterNames = {"con", "rw"}, behavior = IO)
     public abstract static class IsOpen extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+
+        static {
+            Casts casts = new Casts(IsOpen.class);
+            CastsHelper.connection(casts);
             casts.arg("rw").asIntegerVector().findFirst();
         }
 
@@ -489,9 +512,10 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "close", visibility = OFF, kind = INTERNAL, parameterNames = {"con", "type"}, behavior = IO)
     public abstract static class Close extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+
+        static {
+            Casts casts = new Casts(Close.class);
+            CastsHelper.connection(casts);
             casts.arg("type").asStringVector().findFirst();
         }
 
@@ -511,13 +535,13 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "readLines", kind = INTERNAL, parameterNames = {"con", "n", "ok", "warn", "encoding", "skipNul"}, behavior = IO)
     public abstract static class ReadLines extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+        static {
+            Casts casts = new Casts(ReadLines.class);
+            CastsHelper.connection(casts);
             casts.arg("n").asIntegerVector().findFirst().notNA();
             casts.arg("ok").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("warn").asLogicalVector().findFirst().notNA().map(toBoolean());
-            Casts.encoding(casts);
+            CastsHelper.encoding(casts);
             casts.arg("skipNul").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
@@ -539,12 +563,13 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "writeLines", visibility = OFF, kind = INTERNAL, parameterNames = {"text", "con", "sep", "useBytes"}, behavior = IO)
     public abstract static class WriteLines extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(WriteLines.class);
             casts.arg("text").asStringVector().mustBe(instanceOf(RAbstractStringVector.class));
-            Casts.connection(casts);
+            CastsHelper.connection(casts);
             casts.arg("sep").asStringVector().findFirst();
-            Casts.useBytes(casts);
+            CastsHelper.useBytes(casts);
         }
 
         @Specialization
@@ -561,9 +586,10 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "flush", visibility = OFF, kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
     public abstract static class Flush extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+
+        static {
+            Casts casts = new Casts(Flush.class);
+            CastsHelper.connection(casts);
         }
 
         @Specialization
@@ -581,10 +607,10 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "pushBack", visibility = OFF, kind = INTERNAL, parameterNames = {"data", "con", "newLine", "type"}, behavior = IO)
     public abstract static class PushBack extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(PushBack.class);
             casts.arg("data").asStringVector().mustBe(instanceOf(RAbstractStringVector.class));
-            Casts.connection(casts);
+            CastsHelper.connection(casts);
             casts.arg("newLine").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("type").asIntegerVector().findFirst();
         }
@@ -599,9 +625,10 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "pushBackLength", kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
     public abstract static class PushBackLength extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+
+        static {
+            Casts casts = new Casts(PushBackLength.class);
+            CastsHelper.connection(casts);
         }
 
         @Specialization
@@ -613,9 +640,9 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "clearPushBack", visibility = OFF, kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
     public abstract static class PushBackClear extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+        static {
+            Casts casts = new Casts(PushBackClear.class);
+            CastsHelper.connection(casts);
         }
 
         @Specialization
@@ -628,11 +655,11 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "readChar", kind = INTERNAL, parameterNames = {"con", "nchars", "useBytes"}, behavior = IO)
     public abstract static class ReadChar extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
-            Casts.nchars(casts);
-            Casts.useBytes(casts);
+        static {
+            Casts casts = new Casts(ReadChar.class);
+            CastsHelper.connection(casts);
+            CastsHelper.nchars(casts);
+            CastsHelper.useBytes(casts);
         }
 
         @SuppressWarnings("unused")
@@ -662,14 +689,15 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "writeChar", visibility = OFF, kind = INTERNAL, parameterNames = {"object", "con", "nchars", "sep", "useBytes"}, behavior = IO)
     public abstract static class WriteChar extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(WriteChar.class);
             casts.arg("object").asStringVector();
             casts.arg("con").defaultError(Message.INVALID_CONNECTION).mustBe(integerValue().or(rawValue())).mapIf(integerValue(),
                             asIntegerVector().setNext(findFirst().integerElement()));
-            Casts.nchars(casts);
+            CastsHelper.nchars(casts);
             casts.arg("sep").allowNull().mustBe(stringValue());
-            Casts.useBytes(casts);
+            CastsHelper.useBytes(casts);
         }
 
         @TruffleBoundary
@@ -717,15 +745,15 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "readBin", kind = INTERNAL, parameterNames = {"con", "what", "n", "size", "signed", "swap"}, behavior = IO)
     public abstract static class ReadBin extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ReadBin.class);
             // TODO con can be a RAWSXP (not implemented)
-            Casts.connection(casts);
+            CastsHelper.connection(casts);
             casts.arg("what").asStringVector().findFirst();
-            Casts.n(casts);
-            Casts.size(casts);
+            CastsHelper.n(casts);
+            CastsHelper.size(casts);
             casts.arg("signed").asLogicalVector().findFirst().notNA().map(toBoolean());
-            Casts.swap(casts);
+            CastsHelper.swap(casts);
         }
 
         @Specialization
@@ -1003,14 +1031,14 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "writeBin", visibility = OFF, kind = INTERNAL, parameterNames = {"object", "con", "size", "swap", "useBytes"}, behavior = IO)
     public abstract static class WriteBin extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(WriteBin.class);
             // TODO atomic, i.e. not RList or RExpression
             casts.arg("object").asVector().mustBe(instanceOf(RAbstractVector.class));
             casts.arg("con").defaultError(Message.INVALID_CONNECTION).mustBe(integerValue().or(rawValue())).mapIf(integerValue(), asIntegerVector().setNext(findFirst().integerElement()));
-            Casts.size(casts);
-            Casts.swap(casts);
-            Casts.useBytes(casts);
+            CastsHelper.size(casts);
+            CastsHelper.swap(casts);
+            CastsHelper.useBytes(casts);
         }
 
         @TruffleBoundary
@@ -1050,8 +1078,8 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "getConnection", kind = INTERNAL, parameterNames = {"what"}, behavior = IO)
     public abstract static class GetConnection extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(GetConnection.class);
             casts.arg("what").asIntegerVector().findFirst();
         }
 
@@ -1078,9 +1106,10 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "isSeekable", kind = INTERNAL, parameterNames = "con", behavior = IO)
     public abstract static class IsSeekable extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+
+        static {
+            Casts casts = new Casts(IsSeekable.class);
+            CastsHelper.connection(casts);
         }
 
         @Specialization
@@ -1092,9 +1121,10 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "seek", kind = INTERNAL, parameterNames = {"con", "where", "origin", "rw"}, behavior = IO)
     public abstract static class Seek extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+
+        static {
+            Casts casts = new Casts(Seek.class);
+            CastsHelper.connection(casts);
             casts.arg("where").asDoubleVector().findFirst();
             casts.arg("origin").asIntegerVector().findFirst();
             casts.arg("rw").asIntegerVector().findFirst();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CopyDFAttr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CopyDFAttr.java
index 491c440ba79dbbd197522d28fb8ce694809b9ff9..d9f2875e1ccb591a09aae6c1cad02f67cb05d411 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CopyDFAttr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CopyDFAttr.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 @RBuiltin(name = "copyDFattr", kind = INTERNAL, parameterNames = {"", ""}, behavior = COMPLEX)
 public abstract class CopyDFAttr extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(CopyDFAttr.class);
+    }
+
     @Specialization()
     protected RAttributable copy(RAbstractContainer in, RAbstractVector out) {
         RVector<?> res = out.materialize();
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 01f77b91cb8a9ebb250b6e31698a7203d1e616b5..842176d6551cdf07ca9ad504d101c6bb22b1757f 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
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -48,8 +47,8 @@ public abstract class Crossprod extends RBuiltinNode {
     @Child private MatMult matMult = MatMultNodeGen.create(/* promoteDimNames: */ false);
     @Child private Transpose transpose;
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Crossprod.class);
         casts.arg("x").mustBe(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()));
     }
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 f23a4ff164e01c69da64d383fc7e844a65bb10d6..236988ed4697a42c9593a61552bdb30ff7c32f3d 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
@@ -25,7 +25,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -47,8 +46,8 @@ public abstract class CumMax extends RBuiltinNode {
     private final NACheck na = NACheck.create();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CumMax.class);
         casts.arg("x").allowNull().mustBe(complexValue().not(), RError.Message.CUMMAX_UNDEFINED_FOR_COMPLEX).mapIf(integerValue().or(logicalValue()), asIntegerVector(true, false, false),
                         asDoubleVector(true, false, false));
     }
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 03076257659619e619db2122a632abc754277a3b..ae28196a601f003886b7738af55b3c9bfe41a2a1 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
@@ -25,7 +25,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -47,8 +46,8 @@ public abstract class CumMin extends RBuiltinNode {
     private final NACheck na = NACheck.create();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CumMin.class);
         casts.arg("x").allowNull().mustBe(complexValue().not(), RError.Message.CUMMIN_UNDEFINED_FOR_COMPLEX).mapIf(integerValue().or(logicalValue()), asIntegerVector(true, false, false),
                         asDoubleVector(true, false, false));
     }
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 20dcf0d352f48b882e8b8647c7df88148d5d2269..ef609bb01119c116b02ced24964414134ca960ac 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
@@ -20,7 +20,6 @@ import java.util.Arrays;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -43,8 +42,8 @@ public abstract class CumProd extends RBuiltinNode {
 
     @Child private BinaryArithmetic mul = BinaryArithmetic.MULTIPLY.createOperation();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CumProd.class);
         casts.arg("x").allowNull().mapIf(complexValue().not(), asDoubleVector(true, false, false));
     }
 
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 92649d60d5859fa40764a4b7a5322bfe26eb14d4..7a1886ac6ee122a9b987e4959dada87ca123bcfa 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
@@ -37,7 +37,6 @@ import java.util.Arrays;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -63,8 +62,8 @@ public abstract class CumSum extends RBuiltinNode {
 
     @Child private BinaryArithmetic add = BinaryArithmetic.ADD.createOperation();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CumSum.class);
         casts.arg("x").allowNull().mapIf(integerValue().or(logicalValue()), asIntegerVector(true, false, false), chain(mapIf(complexValue().not(), asDoubleVector(true, false, false))).end());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DPut.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DPut.java
index f3621cd18b11f21d9f71fcad1e2884c95381103d..8a7255109242749be6f443c5dc4f98131ede3bbc 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DPut.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DPut.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,6 @@ import java.io.IOException;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RDeparse;
 import com.oracle.truffle.r.runtime.RError;
@@ -44,8 +43,8 @@ import com.oracle.truffle.r.runtime.conn.RConnection;
 @RBuiltin(name = "dput", visibility = OFF, kind = INTERNAL, parameterNames = {"x", "file", "opts"}, behavior = IO)
 public abstract class DPut extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(DPut.class);
         casts.arg("file").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
         casts.arg("opts").asIntegerVector().findFirst();
     }
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 8709521c226523cb7b6e9f1f64463ff6f4745378..f5ea8c6b09eca0a406161cac73c4fa708cfb6b22 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
@@ -40,7 +40,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -140,8 +139,8 @@ public class DatePOSIXFunctions {
 
         @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Date2POSIXlt.class);
             casts.arg("x").mapNull(emptyDoubleVector()).asDoubleVector();
         }
 
@@ -176,8 +175,8 @@ public class DatePOSIXFunctions {
 
         @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(AsPOSIXlt.class);
             casts.arg("x").mapNull(emptyDoubleVector()).asDoubleVector(true, false, false);
             casts.arg("tz").asStringVector().findFirst("");
         }
@@ -216,8 +215,8 @@ public class DatePOSIXFunctions {
     @RBuiltin(name = "as.POSIXct", kind = INTERNAL, parameterNames = {"x", "tz"}, behavior = READS_STATE)
     public abstract static class AsPOSIXct extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(AsPOSIXct.class);
             casts.arg("x").mustBe(RAbstractListVector.class);
             casts.arg("tz").asStringVector().findFirst("");
         }
@@ -275,8 +274,8 @@ public class DatePOSIXFunctions {
     public abstract static class POSIXlt2Date extends RBuiltinNode {
         private static final RStringVector CLASS_ATTR = (RStringVector) RDataFactory.createStringVectorFromScalar("Date").makeSharedPermanent();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(POSIXlt2Date.class);
             casts.arg("x").mustBe(RAbstractListVector.class);
         }
 
@@ -333,8 +332,8 @@ public class DatePOSIXFunctions {
             // TODO: find a proper source for this mapping
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FormatPOSIXlt.class);
             casts.arg("x").mustBe(RAbstractListVector.class);
             casts.arg("format").asStringVector().mustBe(notEmpty());
             casts.arg("usetz").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
@@ -391,8 +390,8 @@ public class DatePOSIXFunctions {
     @RBuiltin(name = "strptime", kind = INTERNAL, parameterNames = {"x", "format", "tz"}, behavior = PURE)
     public abstract static class StrPTime extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(StrPTime.class);
             casts.arg("x").mapNull(emptyStringVector()).asStringVector();
             casts.arg("format").mapNull(emptyStringVector()).asStringVector();
             casts.arg("tz").mapNull(emptyStringVector()).asStringVector();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java
index a4ed591f4a180e85358173bb53b0c57a4346d00d..61b783d1babb10385736fba542df72d3a78d9159 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.helpers.DebugHandling;
 import com.oracle.truffle.r.runtime.RError;
@@ -43,9 +42,11 @@ public class DebugFunctions {
 
     protected abstract static class ErrorAndFunAdapter extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("fun").mustBe(RFunction.class, Message.ARG_MUST_BE_CLOSURE);
+        static final class ErrorAndFunCasts extends Casts {
+            ErrorAndFunCasts(Class<? extends ErrorAndFunAdapter> extCls) {
+                super(extCls);
+                casts.arg("fun").mustBe(RFunction.class, Message.ARG_MUST_BE_CLOSURE);
+            }
         }
 
         protected void doDebug(RFunction fun, Object text, Object condition, boolean once) throws RError {
@@ -58,9 +59,14 @@ public class DebugFunctions {
         }
     }
 
+    @SuppressWarnings("unused")
     @RBuiltin(name = "debug", visibility = OFF, kind = INTERNAL, parameterNames = {"fun", "text", "condition"}, behavior = COMPLEX)
     public abstract static class Debug extends ErrorAndFunAdapter {
 
+        static {
+            new ErrorAndFunCasts(Debug.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected RNull doDebug(RFunction fun, Object text, Object condition) {
@@ -69,9 +75,14 @@ public class DebugFunctions {
         }
     }
 
+    @SuppressWarnings("unused")
     @RBuiltin(name = "debugonce", visibility = OFF, kind = INTERNAL, parameterNames = {"fun", "text", "condition"}, behavior = COMPLEX)
     public abstract static class DebugOnce extends ErrorAndFunAdapter {
 
+        static {
+            new ErrorAndFunCasts(DebugOnce.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected RNull debugonce(RFunction fun, Object text, Object condition) {
@@ -81,9 +92,14 @@ public class DebugFunctions {
         }
     }
 
+    @SuppressWarnings("unused")
     @RBuiltin(name = "undebug", visibility = OFF, kind = INTERNAL, parameterNames = {"fun"}, behavior = COMPLEX)
     public abstract static class UnDebug extends ErrorAndFunAdapter {
 
+        static {
+            new ErrorAndFunCasts(UnDebug.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected RNull undebug(RFunction func) {
@@ -94,9 +110,14 @@ public class DebugFunctions {
         }
     }
 
+    @SuppressWarnings("unused")
     @RBuiltin(name = "isdebugged", kind = INTERNAL, parameterNames = {"fun"}, behavior = PURE)
     public abstract static class IsDebugged extends ErrorAndFunAdapter {
 
+        static {
+            new ErrorAndFunCasts(IsDebugged.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected byte isDebugged(RFunction func) {
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 defed06f112de37f4d93a3230c7e94f81f9a9fc9..6db3144a985f4b5e0db857ba8b6aca1614d50193 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
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.RASTUtils;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -49,8 +48,8 @@ public abstract class DelayedAssign extends RBuiltinNode {
 
     private final BranchProfile errorProfile = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(DelayedAssign.class);
         casts.arg("x").mustBe(stringValue()).asStringVector().mustBe(notEmpty(), RError.Message.INVALID_FIRST_ARGUMENT).findFirst();
         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));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Deparse.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Deparse.java
index 8fb0d1ffbe14d540b1957761085e9368f164a9dd..e1abc2461e3fb24e568e8b3381d71c5469c2585a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Deparse.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Deparse.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -17,7 +17,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RDeparse;
 import com.oracle.truffle.r.runtime.RError;
@@ -31,8 +30,8 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 @RBuiltin(name = "deparse", kind = INTERNAL, parameterNames = {"expr", "width.cutoff", "backtick", "control", "nlines"}, behavior = PURE)
 public abstract class Deparse extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Deparse.class);
         casts.arg("width.cutoff").asIntegerVector().findFirst(0);
         casts.arg("backtick").asLogicalVector().findFirst(RRuntime.LOGICAL_TRUE).map(toBoolean());
         casts.arg("control").asIntegerVector().findFirst();
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 b8130992c80cc11e3786415aff64f48aa678dd0d..6ddd7cabaf0a63f137a4dea068a2dfaeadcce128 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
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1998-2013, The R Core Team
  * Copyright (c) 2003-2015, The R Foundation
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -21,7 +21,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -37,8 +36,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 @RBuiltin(name = "diag", kind = INTERNAL, parameterNames = {"x", "nrow", "ncol"}, behavior = PURE)
 public abstract class Diag extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Diag.class);
         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/Dim.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Dim.java
index f9af807d25e52c27151f9c6437185a71c28e7762..9e495172e5ddfa9b633c73da7eaff65ecf8fc582 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Dim.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Dim.java
@@ -39,6 +39,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 @RBuiltin(name = "dim", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
 public abstract class Dim extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(Dim.class);
+    }
+
     @Specialization
     protected Object dim(RAbstractContainer container,
                     @Cached("createBinaryProfile()") ConditionProfile hasDimensionsProfile,
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java
index 0de9caa23a61d369a9b1b29fd250c4c87f07e3f5..2993a023e58813ab9b89c0b08244068e5eaf09ad 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java
@@ -41,6 +41,10 @@ public abstract class DimNames extends RBuiltinNode {
 
     private final ConditionProfile nullProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(DimNames.class);
+    }
+
     @Specialization(guards = "!isRAbstractContainer(operand)")
     protected RNull getDimNames(@SuppressWarnings("unused") Object operand) {
         return RNull.instance;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
index e5eba227ee8fa5d4a43a4356a5fe5ecfbc70996b..9976ccbaa8c3addfb04bec75e50d1f3757b4eaef 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
@@ -38,7 +38,6 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.GetFunctions.Get;
 import com.oracle.truffle.r.nodes.builtin.base.GetFunctionsFactory.GetNodeGen;
@@ -80,8 +79,8 @@ public abstract class DoCall extends RBuiltinNode implements InternalRSyntaxNode
 
     @Child private RExplicitCallNode call = RExplicitCallNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(DoCall.class);
         casts.arg("what").defaultError(Message.MUST_BE_STRING_OR_FUNCTION, "what").mustBe(instanceOf(RFunction.class).or(stringValue()));
         casts.arg("args").mustBe(RAbstractListVector.class, Message.SECOND_ARGUMENT_LIST);
         casts.arg("quote").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Drop.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Drop.java
index 5edaedbcbe3deb34d6e44342fde765197ca61fee..295782ffeddd39e036218c3ec8828e504f35691d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Drop.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Drop.java
@@ -50,6 +50,10 @@ public abstract class Drop extends RBuiltinNode {
     private final ConditionProfile resultIsScalarProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile noDimNamesProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(Drop.class);
+    }
+
     @Specialization
     protected RAbstractVector doDrop(RAbstractVector x,
                     @Cached("create()") GetDimAttributeNode getDimsNode,
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 d137a43dd3201dd02b3b54b718642402b75f0997..88cf01b06e6e32aa2d74fafed15d5860792b897f 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
@@ -46,7 +46,7 @@ public class DuplicatedFunctions {
 
         private final ConditionProfile incomparable = ConditionProfile.createBinaryProfile();
 
-        protected void casts(CastBuilder casts) {
+        protected static void casts(Casts casts) {
             // these are similar to those in DuplicatedFunctions.java
             casts.arg("x").mapNull(emptyList()).mustBe(abstractVectorValue(), RError.SHOW_CALLER,
                             RError.Message.APPLIES_TO_VECTORS,
@@ -85,8 +85,8 @@ public class DuplicatedFunctions {
     @RBuiltin(name = "duplicated", kind = INTERNAL, parameterNames = {"x", "incomparables", "fromLast", "nmax"}, behavior = PURE)
     public abstract static class Duplicated extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Duplicated.class);
             casts(casts);
             // currently not supported and not tested, but NA is a correct value (the same for empty
             // vectors) whereas 0 is not (throws an error)
@@ -132,8 +132,8 @@ public class DuplicatedFunctions {
     @RBuiltin(name = "anyDuplicated", kind = INTERNAL, parameterNames = {"x", "incomparables", "fromLast"}, behavior = PURE)
     public abstract static class AnyDuplicated extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(AnyDuplicated.class);
             casts(casts);
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
index 5caba014473e6eb07e761b757e17bc4050bf4530..688dd47a2c24c7b206eb193eb929fc91085cde1b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
@@ -38,7 +38,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -62,8 +61,8 @@ public class DynLoadFunctions {
     public abstract static class DynLoad extends RBuiltinNode {
         @Child private DLL.LoadPackageDLLNode loadPackageDLLNode = DLL.LoadPackageDLLNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(DynLoad.class);
             casts.arg("lib").mustBe(stringValue()).asStringVector().mustBe(size(1), RError.Message.CHAR_ARGUMENT).findFirst();
             casts.arg("local").asLogicalVector().findFirst().map(toBoolean());
             casts.arg("now").asLogicalVector().findFirst().map(toBoolean());
@@ -86,8 +85,8 @@ public class DynLoadFunctions {
     public abstract static class DynUnload extends RBuiltinNode {
         @Child DLL.UnloadNode dllUnloadNode = DLL.UnloadNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(DynUnload.class);
             casts.arg("lib").mustBe(stringValue()).asStringVector().mustBe(size(1), RError.Message.CHAR_ARGUMENT).findFirst();
         }
 
@@ -130,8 +129,8 @@ public class DynLoadFunctions {
     public abstract static class IsLoaded extends RBuiltinNode {
         @Child DLL.RFindSymbolNode findSymbolNode = DLL.RFindSymbolNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(IsLoaded.class);
             casts.arg("symbol").mustBe(stringValue()).asStringVector().mustBe(notEmpty()).findFirst();
             casts.arg("PACKAGE").mustBe(stringValue()).asStringVector().mustBe(notEmpty()).findFirst();
             casts.arg("type").mustBe(stringValue()).asStringVector().mustBe(notEmpty()).findFirst();
@@ -166,8 +165,8 @@ public class DynLoadFunctions {
     public abstract static class GetSymbolInfo extends RBuiltinNode {
         @Child DLL.RFindSymbolNode findSymbolNode = DLL.RFindSymbolNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(GetSymbolInfo.class);
             casts.arg("symbol").mustBe(stringValue()).asStringVector().mustBe(notEmpty()).findFirst();
             casts.arg("withRegistrationInfo").mustBe(logicalValue()).asLogicalVector().findFirst().map(toBoolean());
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodeString.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodeString.java
index 929833c85db81011d1549b1da642863bad781377..2cdec5a98cd8b5e42dffc9cff0b8dfe6c72a0ef1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodeString.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodeString.java
@@ -24,7 +24,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -49,8 +48,8 @@ public abstract class EncodeString extends RBuiltinNode {
     private final NACheck na = NACheck.create();
     private final BranchProfile everSeenNA = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(EncodeString.class);
         casts.arg("x").mustBe(stringValue(), RError.Message.CHAR_VEC_ARGUMENT);
 
         casts.arg("width").asIntegerVector().findFirst().mustBe(intNA().or(gte0()));
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 9e6d68c9d4c68752bb3aefbe97a02b8b438172a1..9b05c97603454440b261b60deb0efcca08517372 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
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -40,8 +39,9 @@ public class EncodingFunctions {
 
     @RBuiltin(name = "Encoding", kind = INTERNAL, parameterNames = "x", behavior = PURE)
     public abstract static class Encoding extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(Encoding.class);
             casts.arg("x").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.CHAR_VEC_ARGUMENT);
         }
 
@@ -54,8 +54,9 @@ public class EncodingFunctions {
 
     @RBuiltin(name = "setEncoding", kind = INTERNAL, parameterNames = {"x", "value"}, behavior = PURE)
     public abstract static class SetEncoding extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SetEncoding.class);
             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").defaultError(RError.SHOW_CALLER, RError.Message.GENERIC, "a character vector 'value' expected").mustBe(stringValue()).asStringVector().mustBe(notEmpty(),
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
index 4c701733800072e93bfb040e117f9705ed7c50c9..f71df176ee575c5d9ef4763d9cfae8d4ff430b3b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
@@ -50,7 +50,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.RRootNode;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RList2EnvNode;
 import com.oracle.truffle.r.nodes.builtin.base.EnvFunctionsFactory.CopyNodeGen;
@@ -95,8 +94,8 @@ public class EnvFunctions {
     @RBuiltin(name = "as.environment", kind = PRIMITIVE, parameterNames = {"fun"}, dispatch = INTERNAL_GENERIC, behavior = COMPLEX)
     public abstract static class AsEnvironment extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(AsEnvironment.class);
             casts.arg("fun").mapIf(numericValue(), asIntegerVector());
         }
 
@@ -231,6 +230,10 @@ public class EnvFunctions {
     @RBuiltin(name = "topenv", kind = INTERNAL, parameterNames = {"envir", "matchThisEnv"}, behavior = COMPLEX)
     public abstract static class TopEnv extends Adapter {
 
+        static {
+            Casts.noCasts(TopEnv.class);
+        }
+
         @Child private FrameFunctions.ParentFrame parentFrameNode;
 
         @Specialization
@@ -281,8 +284,8 @@ public class EnvFunctions {
     @RBuiltin(name = "parent.env", kind = INTERNAL, parameterNames = {"env"}, behavior = READS_FRAME)
     public abstract static class ParentEnv extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ParentEnv.class);
             casts.arg("env").mustBe(instanceOf(REnvironment.class), RError.SHOW_CALLER, Message.ARGUMENT_NOT_ENVIRONMENT);
         }
 
@@ -299,8 +302,8 @@ public class EnvFunctions {
     @RBuiltin(name = "parent.env<-", kind = INTERNAL, parameterNames = {"env", "value"}, behavior = COMPLEX)
     public abstract static class SetParentEnv extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SetParentEnv.class);
             casts.arg("env").mustBe(instanceOf(REnvironment.class), Message.NON_LANG_ASSIGNMENT_TARGET);
             casts.arg("value").mustNotBeNull(Message.USE_NULL_ENV_DEFUNCT, "NULL").mustBe(instanceOf(REnvironment.class), Message.ARGUMENT_NAME_NOT_ENVIRONMENT, "parent");
         }
@@ -319,6 +322,10 @@ public class EnvFunctions {
     @RBuiltin(name = "is.environment", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsEnvironment extends RBuiltinNode {
 
+        static {
+            Casts.noCasts(IsEnvironment.class);
+        }
+
         @Specialization
         protected byte isEnvironment(Object env) {
             return env instanceof REnvironment ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE;
@@ -331,6 +338,10 @@ public class EnvFunctions {
         private final ConditionProfile attributable = ConditionProfile.createBinaryProfile();
         @Child private GetFixedAttributeNode getEnvAttrNode;
 
+        static {
+            Casts.noCasts(Environment.class);
+        }
+
         @Specialization
         protected Object environment(VirtualFrame frame, @SuppressWarnings("unused") RNull fun,
                         @Cached("new()") GetCallerFrameNode callerFrame,
@@ -390,8 +401,8 @@ public class EnvFunctions {
     @RBuiltin(name = "environment<-", kind = PRIMITIVE, parameterNames = {"env", "value"}, behavior = COMPLEX)
     public abstract static class UpdateEnvironment extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(UpdateEnvironment.class);
             casts.arg("value").allowNull().mustBe(REnvironment.class, Message.REPLACEMENT_NOT_ENVIRONMENT);
         }
 
@@ -464,6 +475,10 @@ public class EnvFunctions {
     @RBuiltin(name = "environmentName", kind = INTERNAL, parameterNames = {"fun"}, behavior = PURE)
     public abstract static class EnvironmentName extends RBuiltinNode {
 
+        static {
+            Casts.noCasts(EnvironmentName.class);
+        }
+
         @Specialization
         protected String environmentName(REnvironment env) {
             return env.getName();
@@ -479,8 +494,8 @@ public class EnvFunctions {
     @RBuiltin(name = "new.env", kind = INTERNAL, parameterNames = {"hash", "parent", "size"}, behavior = COMPLEX)
     public abstract static class NewEnv extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(NewEnv.class);
             casts.arg("hash").mustNotBeNull().asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
             casts.arg("parent").mustBe(REnvironment.class, Message.MUST_BE_ENVIRON);
             casts.arg("size").mustNotBeNull().asIntegerVector().findFirst(0);
@@ -506,8 +521,8 @@ public class EnvFunctions {
     @RBuiltin(name = "lockEnvironment", visibility = OFF, kind = INTERNAL, parameterNames = {"env", "bindings"}, behavior = COMPLEX)
     public abstract static class LockEnvironment extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(LockEnvironment.class);
             casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
             // TODO: the actual interpretation of this parameter remains dubious
             casts.arg("bindings").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
@@ -523,8 +538,8 @@ public class EnvFunctions {
     @RBuiltin(name = "environmentIsLocked", kind = INTERNAL, parameterNames = {"env"}, behavior = PURE)
     public abstract static class EnvironmentIsLocked extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(EnvironmentIsLocked.class);
             casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
         }
 
@@ -537,8 +552,8 @@ public class EnvFunctions {
     @RBuiltin(name = "lockBinding", visibility = OFF, kind = INTERNAL, parameterNames = {"sym", "env"}, behavior = COMPLEX)
     public abstract static class LockBinding extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(LockBinding.class);
             casts.arg("sym").mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
             casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
         }
@@ -553,8 +568,8 @@ public class EnvFunctions {
     @RBuiltin(name = "unlockBinding", visibility = OFF, kind = INTERNAL, parameterNames = {"sym", "env"}, behavior = COMPLEX)
     public abstract static class UnlockBinding extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(UnlockBinding.class);
             casts.arg("sym").mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
             casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
         }
@@ -569,8 +584,8 @@ public class EnvFunctions {
     @RBuiltin(name = "bindingIsLocked", kind = INTERNAL, parameterNames = {"sym", "env"}, behavior = PURE)
     public abstract static class BindingIsLocked extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(BindingIsLocked.class);
             casts.arg("sym").mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
             casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
         }
@@ -584,8 +599,8 @@ public class EnvFunctions {
     @RBuiltin(name = "makeActiveBinding", visibility = OFF, kind = INTERNAL, parameterNames = {"sym", "fun", "env"}, behavior = COMPLEX)
     public abstract static class MakeActiveBinding extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(MakeActiveBinding.class);
             casts.arg("sym").mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
             casts.arg("fun").mustBe(RFunction.class, RError.SHOW_CALLER, Message.NOT_A_FUNCTION);
             casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
@@ -602,8 +617,8 @@ public class EnvFunctions {
     @RBuiltin(name = "bindingIsActive", kind = INTERNAL, parameterNames = {"sym", "env"}, behavior = PURE)
     public abstract static class BindingIsActive extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(BindingIsActive.class);
             casts.arg("sym").mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
             casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
         }
@@ -621,8 +636,8 @@ public class EnvFunctions {
 
         @Child private CopyNode copy;
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(EnvToList.class);
             casts.arg("x").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
             casts.arg("all.names").mustNotBeNull().asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
             casts.arg("sorted").mustNotBeNull().asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Eval.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Eval.java
index aba09031a868723789bc7c17e3b7efdd2c8c5736..3367d84ad0838348813259ff5493955ce0d695d6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Eval.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Eval.java
@@ -37,7 +37,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.EvalNodeGen.EvalEnvCastNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.FrameFunctions.SysFrame;
@@ -134,13 +133,11 @@ public abstract class Eval extends RBuiltinNode {
     @Child private EvalEnvCast envCast = EvalEnvCastNodeGen.create();
     @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        // @formatter:off
-        casts.arg("envir").allowNull().mustBe(instanceOf(REnvironment.class).or(instanceOf(RList.class)).or(instanceOf(RPairList.class)).or(numericValue())).
-                mapIf(numericValue(), chain(asIntegerVector()).with(mustBe(singleElement())).with(findFirst().integerElement()).end());
+    static {
+        Casts casts = new Casts(Eval.class);
+        casts.arg("envir").allowNull().mustBe(instanceOf(REnvironment.class).or(instanceOf(RList.class)).or(instanceOf(RPairList.class)).or(numericValue())).mapIf(numericValue(),
+                        chain(asIntegerVector()).with(mustBe(singleElement())).with(findFirst().integerElement()).end());
         casts.arg("enclos").allowNull().mustBe(REnvironment.class);
-        // @formatter:on
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Exists.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Exists.java
index e70b055c123b0f7e907fa223ab80bec3434eba1b..f08f18daa3dc3478474890ca9636265be26f71f3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Exists.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Exists.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNodeGen;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -52,8 +51,8 @@ public abstract class Exists extends RBuiltinNode {
      */
     public abstract byte execute(String nameVec, REnvironment env, String mode, boolean inherits);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Exists.class);
         casts.arg("x").mustBe(stringValue(), Message.INVALID_FIRST_ARGUMENT).asStringVector().findFirst();
         casts.arg("envir").mustBe(REnvironment.class);
         casts.arg("mode").mustBe(stringValue()).asStringVector().findFirst();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java
index a0c481ef01afc35a7d93f9f1309407fd2debe721..f4b9d0c8e54fa4bd3fc9f9798019d4f8278b0496 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,10 @@ public abstract class Expression extends RBuiltinNode {
      */
     private final ConditionProfile isEvaluatedProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(Expression.class);
+    }
+
     @Specialization
     @ExplodeLoop
     protected Object doExpression(RArgsValuesAndNames args) {
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 c6e17bcdab114c70593b55d210bc37bc62186916..5534dd45050b4bc9447f05bdc8bc2ab287a97d30 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
@@ -59,7 +59,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
@@ -93,8 +92,8 @@ public class FileFunctions {
         private static final int WRITE = 2;
         private static final int READ = 4;
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FileAccess.class);
             casts.arg("names").mustBe(stringValue()).asStringVector();
             casts.arg("mode").asIntegerVector().findFirst().mustBe(gte(0).and(lte(7)));
         }
@@ -125,8 +124,9 @@ public class FileFunctions {
 
     @RBuiltin(name = "file.append", kind = INTERNAL, parameterNames = {"file1", "file2"}, behavior = IO)
     public abstract static class FileAppend extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(FileAppend.class);
             casts.arg("file1").mustBe(stringValue()).asStringVector();
             casts.arg("file2").mustBe(stringValue()).asStringVector();
         }
@@ -220,8 +220,9 @@ public class FileFunctions {
 
     @RBuiltin(name = "file.create", kind = INTERNAL, parameterNames = {"vec", "showWarnings"}, behavior = IO)
     public abstract static class FileCreate extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(FileCreate.class);
             casts.arg("vec").mustBe(stringValue()).asStringVector();
             casts.arg("showWarnings").asLogicalVector().findFirst().mapIf(logicalNA(), constant(RRuntime.LOGICAL_FALSE));
         }
@@ -266,8 +267,8 @@ public class FileFunctions {
 
         @Child private SetClassAttributeNode setClassAttrNode;
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FileInfo.class);
             casts.arg("extra_cols").asLogicalVector().findFirst().map(toBoolean());
         }
 
@@ -423,8 +424,9 @@ public class FileFunctions {
     }
 
     private abstract static class FileLinkAdaptor extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(FileLinkAdaptor.class);
             casts.arg("from").mustBe(stringValue(), RError.Message.INVALID_FIRST_FILENAME).asStringVector();
             casts.arg("to").mustBe(stringValue(), RError.Message.INVALID_SECOND_FILENAME).asStringVector();
         }
@@ -487,8 +489,8 @@ public class FileFunctions {
     @RBuiltin(name = "file.remove", kind = INTERNAL, parameterNames = {"file"}, behavior = IO)
     public abstract static class FileRemove extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FileRemove.class);
             casts.arg("file").mustBe(stringValue(), RError.Message.INVALID_FIRST_FILENAME).asStringVector();
         }
 
@@ -515,8 +517,9 @@ public class FileFunctions {
 
     @RBuiltin(name = "file.rename", kind = INTERNAL, parameterNames = {"from", "to"}, behavior = IO)
     public abstract static class FileRename extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(FileRename.class);
             casts.arg("from").mustBe(stringValue()).asStringVector();
             casts.arg("to").mustBe(stringValue()).asStringVector();
         }
@@ -551,8 +554,8 @@ public class FileFunctions {
     @RBuiltin(name = "file.exists", kind = INTERNAL, parameterNames = {"file"}, behavior = IO)
     public abstract static class FileExists extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FileExists.class);
             casts.arg("file").mustBe(stringValue()).asStringVector();
         }
 
@@ -580,8 +583,8 @@ public class FileFunctions {
         private static final String DOT = ".";
         private static final String DOTDOT = "..";
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ListFiles.class);
             casts.arg("path").mustBe(stringValue()).asStringVector();
             casts.arg("pattern").allowNull().mustBe(stringValue());
             casts.arg("all.files").asLogicalVector().findFirst().notNA().map(toBoolean());
@@ -721,8 +724,9 @@ public class FileFunctions {
 
     @RBuiltin(name = "list.dirs", kind = INTERNAL, parameterNames = {"directory", "full.names", "recursive"}, behavior = IO)
     public abstract static class ListDirs extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(ListDirs.class);
             casts.arg("directory").mustBe(stringValue()).asStringVector();
             casts.arg("full.names").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("recursive").asLogicalVector().findFirst().notNA().map(toBoolean());
@@ -777,8 +781,8 @@ public class FileFunctions {
     @RBuiltin(name = "file.path", kind = INTERNAL, parameterNames = {"paths", "fsep"}, behavior = IO)
     public abstract static class FilePath extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FilePath.class);
             casts.arg("paths").mustBe(instanceOf(RList.class), RError.Message.INVALID_FIRST_ARGUMENT);
             casts.arg("fsep").mustBe(stringValue()).asStringVector().findFirst().notNA();
         }
@@ -876,8 +880,8 @@ public class FileFunctions {
     @RBuiltin(name = "file.copy", kind = INTERNAL, parameterNames = {"from", "to", "overwrite", "recursive", "copy.mode", "copy.date"}, behavior = IO)
     public abstract static class FileCopy extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FileCopy.class);
             casts.arg("from").mustBe(stringValue()).asStringVector();
             casts.arg("to").mustBe(stringValue()).asStringVector();
             casts.arg("overwrite").asLogicalVector().findFirst().notNA().map(toBoolean());
@@ -1011,8 +1015,8 @@ public class FileFunctions {
     @RBuiltin(name = "file.show", kind = INTERNAL, parameterNames = {"files", "header", "title", "delete.file", "pager"}, visibility = OFF, behavior = IO)
     public abstract static class FileShow extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FileShow.class);
             casts.arg("files").asStringVector();
             casts.arg("header").asStringVector();
             casts.arg("title").asStringVector();
@@ -1068,8 +1072,9 @@ public class FileFunctions {
 
     @RBuiltin(name = "dirname", kind = INTERNAL, parameterNames = {"path"}, behavior = IO)
     public abstract static class DirName extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(DirName.class);
             casts.arg("path").mustBe(stringValue(), RError.Message.CHAR_VEC_ARGUMENT);
         }
 
@@ -1087,8 +1092,8 @@ public class FileFunctions {
     @RBuiltin(name = "basename", kind = INTERNAL, parameterNames = {"path"}, behavior = IO)
     public abstract static class BaseName extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(BaseName.class);
             casts.arg("path").mustBe(stringValue(), RError.Message.CHAR_VEC_ARGUMENT);
         }
 
@@ -1106,8 +1111,8 @@ public class FileFunctions {
     @RBuiltin(name = "unlink", visibility = OFF, kind = INTERNAL, parameterNames = {"x", "recursive", "force"}, behavior = IO)
     public abstract static class Unlink extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Unlink.class);
             casts.arg("x").mustBe(stringValue(), RError.Message.CHAR_VEC_ARGUMENT);
             casts.arg("recursive").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("force").asLogicalVector().findFirst().notNA().map(toBoolean());
@@ -1175,8 +1180,8 @@ public class FileFunctions {
     @RBuiltin(name = "dir.create", visibility = OFF, kind = INTERNAL, parameterNames = {"path", "showWarnings", "recursive", "mode"}, behavior = IO)
     public abstract static class DirCreate extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(DirCreate.class);
             casts.arg("path").mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
             casts.arg("showWarnings").asLogicalVector().findFirst().map(toBoolean());
             casts.arg("recursive").asLogicalVector().findFirst().map(toBoolean());
@@ -1232,8 +1237,9 @@ public class FileFunctions {
 
     @RBuiltin(name = "dir.exists", kind = INTERNAL, parameterNames = "paths", behavior = IO)
     public abstract static class DirExists extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(DirExists.class);
             casts.arg("paths").mustBe(stringValue()).asStringVector();
         }
 
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 39e733fef1823dde286cd2a08816303df636c05e..605e55f3fb557cbafdb69fdae364aea1b56d8296 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
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RType;
@@ -47,16 +46,10 @@ public abstract class Floor extends UnaryArithmeticBuiltinNode {
         super(RType.Double, RError.Message.NON_NUMERIC_MATH, null);
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        //@formatter:off
-        casts.arg("x").
-            defaultError(this, RError.Message.NON_NUMERIC_MATH).
-            mustNotBeNull().
-            mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).
-            mustBe(numericValue()).
-            asDoubleVector(true, true, true);
-        //@formatter:on
+    static {
+        Casts casts = new Casts(Floor.class);
+        casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustNotBeNull().mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue()).asDoubleVector(true,
+                        true, true);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForceAndCall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForceAndCall.java
index 6dc5964db0e40b081e02b7204a862bbb3fa8923a..3368086a659ce6075b865ceb209bfabdbddb19b2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForceAndCall.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForceAndCall.java
@@ -31,7 +31,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
 import com.oracle.truffle.r.nodes.function.call.RExplicitCallNode;
@@ -48,8 +47,8 @@ public abstract class ForceAndCall extends RBuiltinNode {
 
     @Child private PromiseHelperNode promiseHelper;
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(ForceAndCall.class);
         casts.arg("n").asIntegerVector().findFirst();
         // TODO other types are possible for FUN that we don't yet handle
         casts.arg("FUN").mustBe(instanceOf(RFunction.class), RError.Message.INVALID_OR_UNIMPLEMENTED_ARGUMENTS);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Formals.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Formals.java
index 0ef6c1371b22d8c1588509d96d2c0bd29c3d63ba..ce083781b25870a75ff9adef33030549d86bac59 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Formals.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Formals.java
@@ -43,6 +43,10 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
 @RBuiltin(name = "formals", kind = INTERNAL, parameterNames = {"fun"}, behavior = PURE)
 public abstract class Formals extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(Formals.class);
+    }
+
     @SuppressWarnings("unused")
     @Specialization(limit = "3", guards = "fun == cachedFunction")
     protected Object formalsCached(RFunction fun,
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
index 5c9e5594e3badf9d2621198dcece5729469fb97e..7c312cd0e9752c17bcd3c7dad0fab5167032b72a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -86,8 +86,8 @@ public abstract class Format extends RBuiltinNode {
         return (RAbstractIntVector) castInteger.execute(operand);
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Format.class);
         casts.arg("x");
         casts.arg("trim").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).notNA().map(toBoolean());
         casts.arg("digits").asIntegerVector().findFirst(RRuntime.INT_NA).mustBe(intNA().or(gte(R_MIN_DIGITS_OPT).and(lte(R_MAX_DIGITS_OPT))));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java
index c69f2dac6af092d2932465d0d8d60fb9974cf2ee..b872f1187f29cf756fad56b82a38f542b7b99f37 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -18,7 +18,6 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
@@ -40,8 +39,8 @@ public abstract class FormatC extends RBuiltinNode {
         return (RStringVector) ((RStringVector) castStringNode.executeString(o)).copyDropAttributes();
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FormatC.class);
         casts.arg("x");
         casts.arg("mode").asStringVector().findFirst();
         casts.arg("width").asIntegerVector().findFirst();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java
index e8bf7b2b5446dc0884a5acb29ce59c8b01a2fd67..109ff35ab3afc3574385174926eee5f95bf7ab74 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java
@@ -45,7 +45,6 @@ import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.RRootNode;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.FrameFunctionsFactory.SysFrameNodeGen;
 import com.oracle.truffle.r.nodes.function.ArgumentMatcher;
@@ -187,8 +186,8 @@ public class FrameFunctions {
     @RBuiltin(name = "sys.call", kind = INTERNAL, parameterNames = {"which"}, behavior = COMPLEX)
     public abstract static class SysCall extends FrameHelper {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SysCall.class);
             casts.arg("which").asIntegerVector().findFirst();
         }
 
@@ -238,8 +237,8 @@ public class FrameFunctions {
             return FrameAccess.READ_ONLY;
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(MatchCall.class);
             casts.arg("definition").mustBe(RFunction.class);
             casts.arg("call").mustBe(RLanguage.class);
             casts.arg("expand.dots").asLogicalVector().findFirst();
@@ -447,8 +446,8 @@ public class FrameFunctions {
             return FrameAccess.MATERIALIZE;
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SysFrame.class);
             casts.arg("which").asIntegerVector().findFirst();
         }
 
@@ -555,8 +554,8 @@ public class FrameFunctions {
         private final BranchProfile promiseProfile = BranchProfile.create();
         private final BranchProfile nonNullCallerProfile = BranchProfile.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SysParent.class);
             casts.arg("n").asIntegerVector().findFirst();
         }
 
@@ -589,8 +588,8 @@ public class FrameFunctions {
             return FrameAccess.READ_ONLY;
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SysFunction.class);
             casts.arg("which").asIntegerVector().findFirst();
         }
 
@@ -661,8 +660,8 @@ public class FrameFunctions {
 
         public abstract REnvironment execute(VirtualFrame frame, int n);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ParentFrame.class);
             casts.arg("n").asIntegerVector().findFirst();
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Gc.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Gc.java
index 4f5573978e11e9fcb57bc9e72ca495c8d375f30d..ad8d21132c6fc067f75dc68ed45e317711fd6812 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Gc.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Gc.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,6 @@ import java.util.Arrays;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -40,8 +39,8 @@ import com.oracle.truffle.r.runtime.data.RDoubleVector;
 @RBuiltin(name = "gc", kind = INTERNAL, parameterNames = {"verbose", "reset"}, behavior = COMPLEX)
 public abstract class Gc extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Gc.class);
         casts.arg("verbose").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("reset").asLogicalVector().findFirst().map(toBoolean());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java
index cc9cc4610d5b5904b84b2414e6b8555aee3ca8e1..2a2ddedc86d4c3646e9a1e66ae271b6ab961dc78 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -25,6 +25,10 @@ public abstract class GetClass extends RBuiltinNode {
 
     @Child private ClassHierarchyNode classHierarchy = ClassHierarchyNodeGen.create(true, false);
 
+    static {
+        Casts.noCasts(GetClass.class);
+    }
+
     @Specialization
     protected RAbstractStringVector getClass(Object x) {
         return classHierarchy.execute(x);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java
index 0fcf141e878c1858f900b504ae53e2dd902eea2c..cae0c2dcee59304515f6848f2c2bed44e1aadd12 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java
@@ -46,7 +46,6 @@ import com.oracle.truffle.r.nodes.RRootNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNodeGen;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.FormalArguments;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
@@ -168,8 +167,8 @@ public class GetFunctions {
 
         public abstract Object execute(VirtualFrame frame, String x, REnvironment environment, String mode, boolean inherits);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Get.class);
             casts.arg("x").mustBe(stringValue()).asStringVector().findFirst();
             casts.arg("envir").mustBe(instanceOf(REnvironment.class).or(integerValue()).or(doubleValue()).or(instanceOf(RS4Object.class))).mapIf(integerValue().or(doubleValue()),
                             chain(asIntegerVector()).with(findFirst().integerElement()).end());
@@ -205,8 +204,8 @@ public class GetFunctions {
 
         private final ConditionProfile inheritsProfile = ConditionProfile.createBinaryProfile();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Get0.class);
             casts.arg("x").mustBe(stringValue()).asStringVector().findFirst();
             casts.arg("envir").mustBe(instanceOf(REnvironment.class).or(integerValue()).or(doubleValue()).or(instanceOf(RS4Object.class))).mapIf(integerValue().or(doubleValue()),
                             chain(asIntegerVector()).with(findFirst().integerElement()).end());
@@ -252,8 +251,8 @@ public class GetFunctions {
 
         @CompilationFinal private boolean needsCallerFrame;
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(MGet.class);
             casts.arg("x").mustBe(stringValue()).asStringVector();
             casts.arg("envir").mustBe(instanceOf(REnvironment.class).or(integerValue()).or(doubleValue()).or(instanceOf(RS4Object.class))).mapIf(integerValue().or(doubleValue()),
                             chain(asIntegerVector()).with(findFirst().integerElement()).end());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetOldClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetOldClass.java
index 26ce406f1cf720e2da49ce66c5a1b3db8d5ff58d..374a9e866f1f6a004bdfea7e950ce74fc0a9d4ca 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetOldClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetOldClass.java
@@ -40,6 +40,10 @@ public abstract class GetOldClass extends RBuiltinNode {
     private final ConditionProfile isObjectProfile = ConditionProfile.createBinaryProfile();
     @Child private GetClassAttributeNode getClassNode = GetClassAttributeNode.create();
 
+    static {
+        Casts.noCasts(GetOldClass.class);
+    }
+
     @Specialization
     protected Object getOldClass(RAbstractContainer arg) {
         if (isObjectProfile.profile(getClassNode.isObject(arg))) {
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 8e7d4ca5a1c09a6d5b4832431a4634a4fbc5972d..32583e1a76f101e2d4245db0411b2c3e814297df 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
@@ -26,7 +26,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -35,8 +34,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "gettext", kind = INTERNAL, parameterNames = {"domain", "args"}, behavior = PURE)
 public abstract class GetText extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(GetText.class);
         casts.arg("domain").asStringVector().findFirst("");
         casts.arg("args").asStringVector();
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
index 762279f9518609c0750dd83411679b2fc07e79a3..2153136a4d169c73bda489beca4a308d2514588a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
@@ -23,6 +23,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
 
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Fallback;
@@ -66,45 +67,45 @@ public class GrepFunctions {
     public abstract static class CommonCodeAdapter extends RBuiltinNode {
         @Child protected PCRERFFI.PCRERFFINode pcreRFFINode = RFFIFactory.getRFFI().getPCRERFFI().createPCRERFFINode();
 
-        protected void castPattern(CastBuilder casts) {
+        protected static void castPattern(Casts casts) {
             // with default error message, NO_CALLER does not work
             casts.arg("pattern").mustBe(stringValue(), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "pattern").asVector().mustBe(notEmpty(), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT,
                             "pattern");
         }
 
-        protected void castText(CastBuilder casts, String textId) {
+        protected static void castText(Casts casts, String textId) {
             casts.arg(textId).mustBe(stringValue(), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, textId);
         }
 
-        protected void castIgnoreCase(CastBuilder casts) {
+        protected static void castIgnoreCase(Casts casts) {
             casts.arg("ignore.case").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
         }
 
-        protected void castPerl(CastBuilder casts) {
+        protected static void castPerl(Casts casts) {
             casts.arg("perl").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
         }
 
-        protected void castFixed(CastBuilder casts, byte defaultValue) {
+        protected static void castFixed(Casts casts, byte defaultValue) {
             casts.arg("fixed").asLogicalVector().findFirst(defaultValue);
         }
 
-        protected void castValue(CastBuilder casts) {
+        protected static void castValue(Casts casts) {
             casts.arg("value").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
         }
 
-        protected void castUseBytes(CastBuilder casts) {
+        protected static void castUseBytes(Casts casts) {
             casts.arg("useBytes").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
         }
 
-        protected void castInvert(CastBuilder casts) {
+        protected static void castInvert(Casts casts) {
             casts.arg("invert").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
         }
 
-        protected void castCosts(CastBuilder casts) {
+        protected static void castCosts(Casts casts) {
             casts.arg("costs").asIntegerVector();
         }
 
-        protected void castBounds(CastBuilder casts) {
+        protected static void castBounds(Casts casts) {
             casts.arg("bounds").asDoubleVector();
         }
 
@@ -319,8 +320,8 @@ public class GrepFunctions {
     @RBuiltin(name = "grep", kind = INTERNAL, parameterNames = {"pattern", "text", "ignore.case", "value", "perl", "fixed", "useBytes", "invert"}, behavior = PURE)
     public abstract static class Grep extends GrepAdapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Grep.class);
             castPattern(casts);
             castText(casts, "text");
             castIgnoreCase(casts);
@@ -342,8 +343,8 @@ public class GrepFunctions {
     @RBuiltin(name = "grepl", kind = INTERNAL, parameterNames = {"pattern", "text", "ignore.case", "value", "perl", "fixed", "useBytes", "invert"}, behavior = PURE)
     public abstract static class GrepL extends GrepAdapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(GrepL.class);
             castPattern(casts);
             castText(casts, "text");
             castIgnoreCase(casts);
@@ -365,7 +366,7 @@ public class GrepFunctions {
 
     protected abstract static class SubAdapter extends CommonCodeAdapter {
 
-        protected void castReplacement(CastBuilder casts) {
+        protected static void castReplacement(Casts casts) {
             // with default error message, NO_CALLER does not work
             casts.arg("replacement").mustBe(stringValue(), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "replacement").asVector().mustBe(notEmpty(), RError.NO_CALLER,
                             RError.Message.INVALID_ARGUMENT, "replacement");
@@ -641,8 +642,8 @@ public class GrepFunctions {
     @RBuiltin(name = "sub", kind = INTERNAL, parameterNames = {"pattern", "replacement", "text", "ignore.case", "perl", "fixed", "useBytes"}, behavior = PURE)
     public abstract static class Sub extends SubAdapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Sub.class);
             castPattern(casts);
             castReplacement(casts);
             castText(casts, "text");
@@ -663,8 +664,8 @@ public class GrepFunctions {
     @RBuiltin(name = "gsub", kind = INTERNAL, parameterNames = {"pattern", "replacement", "text", "ignore.case", "perl", "fixed", "useBytes"}, behavior = PURE)
     public abstract static class GSub extends SubAdapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(GSub.class);
             castPattern(casts);
             castReplacement(casts);
             castText(casts, "text");
@@ -692,8 +693,8 @@ public class GrepFunctions {
         @Child SetFixedAttributeNode setCaptureNamesAttrNode = SetFixedAttributeNode.create("capture.names");
         @Child SetFixedAttributeNode setDimNamesAttrNode = SetFixedAttributeNode.createDimNames();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Regexp.class);
             castPattern(casts);
             castText(casts, "text");
             castIgnoreCase(casts);
@@ -880,8 +881,8 @@ public class GrepFunctions {
         @Child SetFixedAttributeNode setCaptureNamesAttrNode = SetFixedAttributeNode.create("capture.names");
         @Child SetFixedAttributeNode setDimNamesAttrNode = SetFixedAttributeNode.createDimNames();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Gregexpr.class);
             castPattern(casts);
             castText(casts, "text");
             castIgnoreCase(casts);
@@ -1019,8 +1020,8 @@ public class GrepFunctions {
     @RBuiltin(name = "agrep", kind = INTERNAL, parameterNames = {"pattern", "x", "ignore.case", "value", "costs", "bounds", "useBytes", "fixed"}, behavior = PURE)
     public abstract static class AGrep extends CommonCodeAdapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(AGrep.class);
             castPattern(casts);
             castText(casts, "x");
             castIgnoreCase(casts);
@@ -1135,8 +1136,8 @@ public class GrepFunctions {
     @RBuiltin(name = "agrepl", kind = INTERNAL, parameterNames = {"pattern", "x", "ignore.case", "value", "costs", "bounds", "useBytes", "fixed"}, behavior = PURE)
     public abstract static class AGrepL extends CommonCodeAdapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(AGrepL.class);
             castPattern(casts);
             castText(casts, "x");
             castIgnoreCase(casts);
@@ -1166,8 +1167,8 @@ public class GrepFunctions {
     @RBuiltin(name = "strsplit", kind = INTERNAL, parameterNames = {"x", "split", "fixed", "perl", "useBytes"}, behavior = PURE)
     public abstract static class Strsplit extends CommonCodeAdapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Strsplit.class);
             casts.arg("x").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.NON_CHARACTER);
             casts.arg("split").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.NON_CHARACTER);
             castFixed(casts, RRuntime.LOGICAL_FALSE);
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 c30b36ab7e5ad1f285953e338957c3fa5f2c1f79..6d4a9370e312e67de7d2ab785a536ca5b552db71 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
@@ -37,7 +37,6 @@ import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
 import com.oracle.truffle.r.nodes.function.RCallNode;
@@ -90,8 +89,8 @@ public class HiddenInternalFunctions {
             }
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(MakeLazy.class);
             casts.arg("names").mustBe(stringValue()).asStringVector();
             casts.arg("eval.env").mustBe(instanceOf(REnvironment.class));
             casts.arg("assign.env").mustBe(instanceOf(REnvironment.class));
@@ -144,8 +143,9 @@ public class HiddenInternalFunctions {
      */
     @RBuiltin(name = "importIntoEnv", kind = INTERNAL, parameterNames = {"impenv", "impnames", "expenv", "expnames"}, behavior = COMPLEX)
     public abstract static class ImportIntoEnv extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(ImportIntoEnv.class);
             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");
@@ -188,8 +188,8 @@ public class HiddenInternalFunctions {
 
         @Child private CallRFunctionCachedNode callCache = CallRFunctionCachedNodeGen.create(2);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(LazyLoadDBFetch.class);
             casts.arg("compressed").asIntegerVector().findFirst();
         }
 
@@ -278,6 +278,10 @@ public class HiddenInternalFunctions {
         private static final RStringVector NAMES = RDataFactory.createStringVector(new String[]{".C", ".Call", ".Fortran", ".External"}, RDataFactory.COMPLETE_VECTOR);
         private static final RStringVector NATIVE_ROUTINE_LIST = RDataFactory.createStringVectorFromScalar("NativeRoutineList");
 
+        static {
+            Casts.noCasts(GetRegisteredRoutines.class);
+        }
+
         @Specialization
         protected RList getRegisteredRoutines(@SuppressWarnings("unused") RNull info) {
             throw RError.error(this, RError.Message.NULL_DLLINFO);
@@ -323,6 +327,10 @@ public class HiddenInternalFunctions {
     public abstract static class GetVarsFromFrame extends RBuiltinNode {
         @Child private PromiseHelperNode promiseHelper;
 
+        static {
+            Casts.noCasts(GetVarsFromFrame.class);
+        }
+
         @Specialization
         protected RList getVarsFromFrame(VirtualFrame frame, RAbstractStringVector varsVec, REnvironment env, byte forceArg) {
             boolean force = RRuntime.fromLogical(forceArg);
@@ -357,8 +365,8 @@ public class HiddenInternalFunctions {
 
         @Child private CallRFunctionCachedNode callCache = CallRFunctionCachedNodeGen.create(2);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(LazyLoadDBinsertValue.class);
             casts.arg("ascii").asIntegerVector().findFirst();
             casts.arg("compsxp").asIntegerVector().findFirst();
         }
@@ -458,6 +466,11 @@ public class HiddenInternalFunctions {
 
     @RBuiltin(name = "lazyLoadDBflush", kind = INTERNAL, parameterNames = "path", behavior = COMPLEX)
     public abstract static class LazyLoadDBFlush extends RBuiltinNode {
+
+        static {
+            Casts.noCasts(LazyLoadDBFlush.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected RNull doLazyLoadDBFlush(RAbstractStringVector dbPath) {
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 a470aa85cc64194336ccdb247259e3249e9b3f94..62b894730ecde4abf897289b4e4561d5e0e1be86 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
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -40,8 +39,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "iconv", kind = INTERNAL, parameterNames = {"x", "from", "to", "sub", "mark", "toRaw"}, behavior = PURE)
 public abstract class IConv extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(IConv.class);
         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").defaultError(RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "from").mustBe(stringValue()).asStringVector().mustBe(size(1));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java
index f1a329fcac628d268a1adc5fe061ed14f7e8df4c..3f5769de6059e2d3da274be8e43051401d5a7aa1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.IterableAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -77,8 +76,8 @@ public abstract class Identical extends RBuiltinNode {
     @Child private IterableAttributeNode attrIterNodeX = IterableAttributeNode.create();
     @Child private IterableAttributeNode attrIterNodeY = IterableAttributeNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Identical.class);
         casts.arg("num.eq").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
         casts.arg("single.NA").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
         casts.arg("attrib.as.set").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InheritsBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InheritsBuiltin.java
index d4c874044f992a6f1cd85801353fb18491f6cab5..b45abeda284522f6bda8d51103d0b086b674529f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InheritsBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InheritsBuiltin.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -20,7 +20,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.InheritsNode;
 import com.oracle.truffle.r.nodes.unary.InheritsNodeGen;
@@ -34,8 +33,8 @@ public abstract class InheritsBuiltin extends RBuiltinNode {
 
     public abstract Object execute(Object x, Object what, Object which);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(InheritsBuiltin.class);
         casts.arg("what").mustBe(stringValue(), NOT_CHARACTER_VECTOR, "what");
         casts.arg("which").mustBe(logicalValue(), NOT_LEN_ONE_LOGICAL_VECTOR, "which").asLogicalVector().findFirst().map(toBoolean());
     }
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 08ed846aeae5384f52ae208eddf5b533622ea339..0b85315703321a178abb85d2a20782ad5fb1d173 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
@@ -26,7 +26,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -37,8 +36,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 @RBuiltin(name = "intToBits", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
 public abstract class IntToBits extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(IntToBits.class);
         casts.arg("x").asIntegerVector();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToUtf8.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToUtf8.java
index 030149ca78691070169dc61e0f9bfabd1493a22d..51a84c924e9abfcbc60145876e037daae5afa825 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToUtf8.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToUtf8.java
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -44,8 +43,8 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 @RBuiltin(name = "intToUtf8", kind = INTERNAL, parameterNames = {"x", "multiple"}, behavior = PURE)
 public abstract class IntToUtf8 extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(IntToUtf8.class);
         casts.arg("x").asIntegerVector();
         casts.arg("multiple").mustNotBeNull().asLogicalVector().findFirst().map(toBoolean());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Invisible.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Invisible.java
index c30e2666760295444d105e320e58ff5963cf58b0..55ec16e7d4e238195b4c80da059c9f524a5b9525 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Invisible.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Invisible.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,10 @@ import com.oracle.truffle.r.runtime.data.RNull;
 @RBuiltin(name = "invisible", visibility = OFF, kind = PRIMITIVE, parameterNames = {"x"}, behavior = COMPLEX)
 public abstract class Invisible extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(Invisible.class);
+    }
+
     @Override
     public Object[] getDefaultParameterValues() {
         return new Object[]{RNull.instance};
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsFiniteFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsFiniteFunctions.java
index c84b1304c65af4a357fbed151719c6fdf5b50871..f1ce895c28b731c223a6d7aff58f444a03e86ec9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsFiniteFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsFiniteFunctions.java
@@ -132,6 +132,10 @@ public class IsFiniteFunctions {
     @RBuiltin(name = "is.finite", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsFinite extends Adapter {
 
+        static {
+            Casts.noCasts(IsFinite.class);
+        }
+
         @Specialization
         protected RLogicalVector doIsFinite(RAbstractDoubleVector vec) {
             return doFunDouble(vec, RRuntime::isFinite);
@@ -166,6 +170,10 @@ public class IsFiniteFunctions {
     @RBuiltin(name = "is.infinite", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsInfinite extends Adapter {
 
+        static {
+            Casts.noCasts(IsInfinite.class);
+        }
+
         @Specialization
         protected RLogicalVector doIsInfinite(RAbstractDoubleVector vec) {
             return doFunDouble(vec, Double::isInfinite);
@@ -190,6 +198,10 @@ public class IsFiniteFunctions {
     @RBuiltin(name = "is.nan", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsNaN extends Adapter {
 
+        static {
+            Casts.noCasts(IsNaN.class);
+        }
+
         private static boolean isNaN(double value) {
             return Double.isNaN(value) && !RRuntime.isNA(value);
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsListFactor.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsListFactor.java
index f7e53501ecb610c53a12c010ad8830382a539cde..48cc21c9563ce13f760332e53ca650e2e6a15229 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsListFactor.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsListFactor.java
@@ -19,7 +19,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.IsListFactorNodeGen.IsListFactorInternalNodeGen;
 import com.oracle.truffle.r.nodes.unary.IsFactorNode;
@@ -70,8 +69,8 @@ public abstract class IsListFactor extends RBuiltinNode {
         }
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(IsListFactor.class);
         casts.arg("recursive").asLogicalVector().findFirst().map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
index 4a85c00052164f5c2ea76442cfab799fb2cdf6ea..39826ee9a75c775a6871bc9507ca43461c737a52 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,6 +64,10 @@ public abstract class IsNA extends RBuiltinNode {
 
     private final ConditionProfile nullDimNamesProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(IsNA.class);
+    }
+
     private Object isNARecursive(Object o) {
         if (recursiveIsNA == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsS4.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsS4.java
index f4b26fcf8a8cb22d73345c7efde39196de4dd194..d4939ab3a5e1d9e3e3688d6edfa20ed44bac55c5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsS4.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsS4.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,10 @@ import com.oracle.truffle.r.runtime.data.RTypedValue;
 @RBuiltin(name = "isS4", kind = PRIMITIVE, parameterNames = {"object"}, behavior = PURE)
 public abstract class IsS4 extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(IsS4.class);
+    }
+
     public abstract byte execute(Object value);
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsSingle.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsSingle.java
index 43baa4688653b1ec46f7f79a962d25bf9f6bf99b..b9d87fff252c7bacefbbd5f4d62d4bb676fcc283 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsSingle.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsSingle.java
@@ -26,7 +26,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -34,8 +33,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 @RBuiltin(name = "is.single", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
 public abstract class IsSingle extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(IsSingle.class);
         casts.arg("x").mustNotBeMissing(RError.Message.ARGUMENTS_PASSED, 0, "'is.single'", 1);
     }
 
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 c8337dda05f32be5101a603711a9998b6514368d..7613e80ff4f84f83d6686e49cb5b001cae6c3e0c 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
@@ -47,6 +47,7 @@ import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RComplex;
@@ -76,15 +77,21 @@ public class IsTypeFunctions {
 
     protected abstract static class MissingAdapter extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("x").mustNotBeMissing((RBaseNode) null, RError.Message.ARGUMENT_MISSING, "x");
+        static final class MissingAdapterCasts extends Casts {
+            MissingAdapterCasts(Class<? extends MissingAdapter> extCls) {
+                super(extCls);
+                casts.arg("x").mustNotBeMissing((RBaseNode) null, RError.Message.ARGUMENT_MISSING, "x");
+            }
         }
     }
 
     @RBuiltin(name = "is.array", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsArray extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsArray.class);
+        }
+
         private final ConditionProfile isArrayProfile = ConditionProfile.createBinaryProfile();
         @Child private GetDimAttributeNode getDim = GetDimAttributeNodeGen.create();
 
@@ -104,6 +111,10 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.recursive", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsRecursive extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsRecursive.class);
+        }
+
         @Specialization
         protected byte isRecursive(RNull arg) {
             return RRuntime.LOGICAL_FALSE;
@@ -134,6 +145,10 @@ public class IsTypeFunctions {
 
         @Child private InheritsCheckNode inheritsFactorCheck = new InheritsCheckNode(RRuntime.CLASS_FACTOR);
 
+        static {
+            new MissingAdapterCasts(IsAtomic.class);
+        }
+
         @Specialization
         protected byte isAtomic(RNull arg) {
             return RRuntime.LOGICAL_TRUE;
@@ -162,6 +177,10 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.call", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsCall extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsCall.class);
+        }
+
         @Specialization
         protected byte isType(RLanguage lang) {
             return RRuntime.LOGICAL_TRUE;
@@ -176,6 +195,10 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.character", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsCharacter extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsCharacter.class);
+        }
+
         @Specialization
         protected byte isType(RAbstractStringVector value) {
             return RRuntime.LOGICAL_TRUE;
@@ -194,6 +217,10 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.complex", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsComplex extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsComplex.class);
+        }
+
         @Specialization
         protected byte isType(RAbstractComplexVector value) {
             return RRuntime.LOGICAL_TRUE;
@@ -212,6 +239,10 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.double", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsDouble extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsDouble.class);
+        }
+
         @Specialization
         protected byte isType(RAbstractDoubleVector value) {
             return RRuntime.LOGICAL_TRUE;
@@ -230,6 +261,10 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.expression", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsExpression extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsExpression.class);
+        }
+
         @Specialization
         protected byte isType(RExpression expr) {
             return RRuntime.LOGICAL_TRUE;
@@ -244,6 +279,10 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.function", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsFunction extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsFunction.class);
+        }
+
         @Specialization
         protected byte isType(RFunction value) {
             return RRuntime.LOGICAL_TRUE;
@@ -258,6 +297,10 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.integer", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsInteger extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsInteger.class);
+        }
+
         @Specialization
         protected byte isType(RAbstractIntVector value) {
             return RRuntime.LOGICAL_TRUE;
@@ -275,6 +318,11 @@ public class IsTypeFunctions {
 
     @RBuiltin(name = "is.language", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsLanguage extends MissingAdapter {
+
+        static {
+            new MissingAdapterCasts(IsLanguage.class);
+        }
+
         @Specialization
         protected byte isType(RSymbol value) {
             return RRuntime.LOGICAL_TRUE;
@@ -301,6 +349,10 @@ public class IsTypeFunctions {
 
         private final ConditionProfile isListProfile = ConditionProfile.createBinaryProfile();
 
+        static {
+            new MissingAdapterCasts(IsList.class);
+        }
+
         public abstract byte execute(Object value);
 
         @Specialization
@@ -322,6 +374,10 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.logical", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsLogical extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsLogical.class);
+        }
+
         @Specialization
         protected byte isType(RAbstractLogicalVector value) {
             return RRuntime.LOGICAL_TRUE;
@@ -343,6 +399,10 @@ public class IsTypeFunctions {
         private final ConditionProfile isMatrixProfile = ConditionProfile.createBinaryProfile();
         @Child private GetDimAttributeNode getDim = GetDimAttributeNodeGen.create();
 
+        static {
+            new MissingAdapterCasts(IsMatrix.class);
+        }
+
         @Specialization
         protected byte isType(RAbstractVector vector) {
             return RRuntime.asLogical(isMatrixProfile.profile(getDim.isMatrix(vector)));
@@ -357,6 +417,10 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.name", aliases = {"is.symbol"}, kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsName extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsName.class);
+        }
+
         @Specialization
         protected byte isType(RSymbol value) {
             return RRuntime.LOGICAL_TRUE;
@@ -371,6 +435,10 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.numeric", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsNumeric extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsNumeric.class);
+        }
+
         @Specialization(guards = "!isFactor(value)")
         protected byte isType(RAbstractIntVector value) {
             return RRuntime.LOGICAL_TRUE;
@@ -405,6 +473,10 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.null", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsNull extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsNull.class);
+        }
+
         @Specialization
         protected byte isType(RNull value) {
             return RRuntime.LOGICAL_TRUE;
@@ -428,6 +500,10 @@ public class IsTypeFunctions {
 
         @Child private GetClassAttributeNode getClassNode = GetClassAttributeNode.create();
 
+        static {
+            Casts.noCasts(IsObject.class);
+        }
+
         public abstract byte execute(Object value);
 
         @Specialization
@@ -443,6 +519,11 @@ public class IsTypeFunctions {
 
     @RBuiltin(name = "is.pairlist", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsPairList extends MissingAdapter {
+
+        static {
+            new MissingAdapterCasts(IsPairList.class);
+        }
+
         @Specialization
         protected byte isType(RNull value) {
             return RRuntime.LOGICAL_TRUE;
@@ -462,6 +543,10 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.raw", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsRaw extends MissingAdapter {
 
+        static {
+            new MissingAdapterCasts(IsRaw.class);
+        }
+
         @Specialization
         protected byte isType(RAbstractRawVector value) {
             return RRuntime.LOGICAL_TRUE;
@@ -486,10 +571,10 @@ public class IsTypeFunctions {
         private final BranchProfile namesAttrProfile = BranchProfile.create();
         @Child private GetFixedAttributeNode namesGetter = GetFixedAttributeNode.createNames();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("x").mustNotBeMissing((RBaseNode) null, RError.Message.ARGUMENT_MISSING, "x");
-            casts.arg("mode").defaultError(this, RError.Message.INVALID_ARGUMENT, "mode").mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
+        static {
+            Casts casts = new Casts(IsVector.class);
+            casts.arg("x").mustNotBeMissing(RError.Message.ARGUMENT_MISSING, "x");
+            casts.arg("mode").defaultError(RError.Message.INVALID_ARGUMENT, "mode").mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
         }
 
         @TruffleBoundary
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsUnsorted.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsUnsorted.java
index c26d7aa2866a30655490715367d1d56eedab22cf..cb571f301f697837038db0d26a26d078740e1dfd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsUnsorted.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsUnsorted.java
@@ -31,7 +31,6 @@ import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.binary.BinaryMapBooleanFunctionNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.Order.CmpNode;
 import com.oracle.truffle.r.nodes.builtin.base.OrderNodeGen.CmpNodeGen;
@@ -55,8 +54,8 @@ public abstract class IsUnsorted extends RBuiltinNode {
 
     private final ConditionProfile strictlyProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(IsUnsorted.class);
         casts.arg("strictly").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).notNA().map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
index 41691b554b1a5521b91e3c006b5793578df1c485..96c4acfe18a082f2b7238b850872f55026dd47aa 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
@@ -38,7 +38,6 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNa
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNodeGen;
@@ -87,10 +86,12 @@ public class LaFunctions {
         protected static final String[] NAMES = new String[]{"values", "vectors"};
         protected final BranchProfile errorProfile = BranchProfile.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("matrix").asDoubleVector(false, true, false).mustBe(squareMatrix(), RError.Message.MUST_BE_SQUARE_NUMERIC, "x");
-            casts.arg("onlyValues").defaultError(RError.Message.INVALID_ARGUMENT, "only.values").asLogicalVector().findFirst().notNA().map(toBoolean());
+        static final class RsgCasts extends Casts {
+            RsgCasts(Class<? extends RsgAdapter> extClass) {
+                super(extClass);
+                casts.arg("matrix").asDoubleVector(false, true, false).mustBe(squareMatrix(), RError.Message.MUST_BE_SQUARE_NUMERIC, "x");
+                casts.arg("onlyValues").defaultError(RError.Message.INVALID_ARGUMENT, "only.values").asLogicalVector().findFirst().notNA().map(toBoolean());
+            }
         }
     }
 
@@ -99,6 +100,10 @@ public class LaFunctions {
 
         private final ConditionProfile hasComplexValues = ConditionProfile.createBinaryProfile();
 
+        static {
+            new RsgCasts(Rg.class);
+        }
+
         @Specialization
         protected Object doRg(RDoubleVector matrix, boolean onlyValues,
                         @Cached("create()") GetDimAttributeNode getDimsNode) {
@@ -193,6 +198,11 @@ public class LaFunctions {
 
     @RBuiltin(name = "La_rs", kind = INTERNAL, parameterNames = {"matrix", "onlyValues"}, behavior = PURE)
     public abstract static class Rs extends RsgAdapter {
+
+        static {
+            new RsgCasts(Rs.class);
+        }
+
         @Specialization
         protected Object doRs(RDoubleVector matrix, boolean onlyValues,
                         @Cached("create()") GetDimAttributeNode getDimsNode) {
@@ -255,8 +265,8 @@ public class LaFunctions {
 
         private final BranchProfile errorProfile = BranchProfile.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Qr.class);
             casts.arg("in").asDoubleVector(false, true, false).mustBe(matrix(), RError.Message.MUST_BE_NUMERIC_MATRIX, "a");
         }
 
@@ -311,8 +321,8 @@ public class LaFunctions {
         private static final char SIDE = 'L';
         private static final char TRANS = 'T';
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(QrCoefReal.class);
             casts.arg("q").mustBe(instanceOf(RList.class));
             casts.arg("b").asDoubleVector(false, true, false).mustBe(matrix(), RError.Message.MUST_BE_NUMERIC_MATRIX, "b");
         }
@@ -379,19 +389,11 @@ public class LaFunctions {
 
         @Child private SetFixedAttributeNode setLogAttrNode = SetFixedAttributeNode.create("logarithm");
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            //@formatter:off
-            casts.arg("a").asDoubleVector(false, true, false).
-                mustBe(matrix(), RError.Message.MUST_BE_NUMERIC_MATRIX, "a").
-                mustBe(squareMatrix(), RError.Message.MUST_BE_SQUARE_MATRIX, "a");
-
-            casts.arg("uselog").defaultError(RError.Message.MUST_BE_LOGICAL, "logarithm").
-                asLogicalVector().
-                findFirst().
-                notNA().
-                map(toBoolean());
-            //@formatter:on
+        static {
+            Casts casts = new Casts(DetGeReal.class);
+            casts.arg("a").asDoubleVector(false, true, false).mustBe(matrix(), RError.Message.MUST_BE_NUMERIC_MATRIX, "a").mustBe(squareMatrix(), RError.Message.MUST_BE_SQUARE_MATRIX, "a");
+
+            casts.arg("uselog").defaultError(RError.Message.MUST_BE_LOGICAL, "logarithm").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
         @Specialization
@@ -465,22 +467,14 @@ public class LaFunctions {
         @Child private SetFixedAttributeNode setPivotAttrNode = SetFixedAttributeNode.create("pivot");
         @Child private SetFixedAttributeNode setRankAttrNode = SetFixedAttributeNode.create("rank");
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            //@formatter:off
-            casts.arg("a").asDoubleVector(false, true, false).
-                mustBe(matrix(), RError.Message.MUST_BE_NUMERIC_MATRIX, "a").
-                mustBe(squareMatrix(), RError.Message.MUST_BE_SQUARE_MATRIX, "a").
-                mustBe(dimGt(1, 0), RError.Message.DIMS_GT_ZERO, "a");
-
-            casts.arg("pivot").asLogicalVector().
-                findFirst().
-                notNA().
-                map(toBoolean());
-
-            casts.arg("tol").asDoubleVector().
-                findFirst(RRuntime.DOUBLE_NA);
-            //@formatter:on
+        static {
+            Casts casts = new Casts(LaChol.class);
+            casts.arg("a").asDoubleVector(false, true, false).mustBe(matrix(), RError.Message.MUST_BE_NUMERIC_MATRIX, "a").mustBe(squareMatrix(), RError.Message.MUST_BE_SQUARE_MATRIX, "a").mustBe(
+                            dimGt(1, 0), RError.Message.DIMS_GT_ZERO, "a");
+
+            casts.arg("pivot").asLogicalVector().findFirst().notNA().map(toBoolean());
+
+            casts.arg("tol").asDoubleVector().findFirst(RRuntime.DOUBLE_NA);
         }
 
         @Specialization
@@ -541,19 +535,14 @@ public class LaFunctions {
             return vec -> vec.getDimensions()[dim];
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            //@formatter:off
-            casts.arg("a").mustBe(numericValue()).asVector().
-                mustBe(matrix(), RError.ROOTNODE, RError.Message.MUST_BE_NUMERIC_MATRIX, "a").
-                mustBe(not(dimEq(0, 0)), RError.ROOTNODE, RError.Message.GENERIC, "'a' is 0-diml").
-                mustBe(squareMatrix(), RError.ROOTNODE, RError.Message.MUST_BE_SQUARE_MATRIX_SPEC, "a", getDimVal(0), getDimVal(1));
+        static {
+            Casts casts = new Casts(LaSolve.class);
+            casts.arg("a").mustBe(numericValue()).asVector().mustBe(matrix(), RError.ROOTNODE, RError.Message.MUST_BE_NUMERIC_MATRIX, "a").mustBe(not(dimEq(0, 0)), RError.ROOTNODE,
+                            RError.Message.GENERIC, "'a' is 0-diml").mustBe(squareMatrix(), RError.ROOTNODE, RError.Message.MUST_BE_SQUARE_MATRIX_SPEC, "a", getDimVal(0), getDimVal(1));
 
-            casts.arg("bin").asDoubleVector(false, true, false).
-                mustBe(or(not(matrix()), not(dimEq(1, 0))), RError.ROOTNODE, RError.Message.GENERIC, "no right-hand side in 'b'");
+            casts.arg("bin").asDoubleVector(false, true, false).mustBe(or(not(matrix()), not(dimEq(1, 0))), RError.ROOTNODE, RError.Message.GENERIC, "no right-hand side in 'b'");
 
             casts.arg("tolin").asDoubleVector().findFirst(RRuntime.DOUBLE_NA);
-            //@formatter:on
         }
 
         @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
index 89f801a70361845bad538f6c77da4d512dd7b1fa..a3bb7941e9bcef3db6f36feceea98a7c45e1d417 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
@@ -33,7 +33,6 @@ import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
 import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
 import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNodeGen;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.LapplyNodeGen.LapplyInternalNodeGen;
 import com.oracle.truffle.r.nodes.control.RLengthNode;
@@ -70,8 +69,8 @@ public abstract class Lapply extends RBuiltinNode {
 
     @Child private LapplyInternalNode lapply = LapplyInternalNodeGen.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Lapply.class);
         // to make conversion of X parameter 100% correct, we'd need to match semantics of
         // asVector() to whatever GNU R is doing there; still this can be a problem only if the
         // internal is called directly (otherwise, it's guaranteed that it's a vector)
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Length.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Length.java
index ae8bc8706610f1c9b9087e945d8707c5491ae08f..df92d3e9fa020cb62fbb1f1212cde43b66c9597d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Length.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Length.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,6 +38,10 @@ public abstract class Length extends RBuiltinNode {
 
     public abstract int executeInt(VirtualFrame frame, Object vector);
 
+    static {
+        Casts.noCasts(Length.class);
+    }
+
     @Specialization
     protected int getLength(VirtualFrame frame, Object vector,
                     @Cached("create()") RLengthNode lengthNode) {
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 e8b4549af008e25a149ead00af1308ddcf1f608f..3b1cff197bee5ae5be5da149591f407b40afd91a 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
@@ -36,7 +36,6 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.control.RLengthNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -52,8 +51,8 @@ public abstract class Lengths extends RBuiltinNode {
 
     @Child private RLengthNode lengthNode;
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Lengths.class);
         casts.arg("x").defaultError(RError.SHOW_CALLER, X_LIST_ATOMIC).allowNull().mustBe(abstractVectorValue());
         casts.arg("use.names").mustBe(numericValue(), RError.SHOW_CALLER, 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/List2Env.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/List2Env.java
index e87f6b36855705860fc21fba64a5dc51b231f37f..f1ab5acbb72b74e7146af06404d35b25accf3af4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/List2Env.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/List2Env.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RList2EnvNode;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -37,8 +36,9 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 
 @RBuiltin(name = "list2env", kind = INTERNAL, parameterNames = {"x", "envir"}, behavior = PURE)
 public abstract class List2Env extends RBuiltinNode {
-    @Override
-    protected void createCasts(CastBuilder casts) {
+
+    static {
+        Casts casts = new Casts(List2Env.class);
         casts.arg("x").mustBe(RAbstractListVector.class, Message.FIRST_ARGUMENT_NOT_NAMED_LIST);
         casts.arg("envir").mustBe(REnvironment.class, Message.MUST_BE_ENVIRON, "envir");
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java
index 2d945ceecfa1af3c142ced1274a1f83b73471621..4ef832ba3320401ac571091b7b156ba78f50344b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java
@@ -32,6 +32,7 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -53,6 +54,10 @@ public abstract class ListBuiltin extends RBuiltinNode {
 
     @CompilationFinal private RStringVector suppliedSignatureArgNames;
 
+    static {
+        Casts.noCasts(ListBuiltin.class);
+    }
+
     /**
      * Creates a shared permanent vector so that it can be re-used for every list(...) with the same
      * arguments.
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 3f9917adf7e2b463ff9a3970d2138bb4d5292539..462f900017a3c52b5ccfb872e0bb94b38b29d762 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
@@ -31,7 +31,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.SerializeFunctions.Adapter;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode;
@@ -60,8 +59,8 @@ public class LoadSaveFunctions {
 
         private final NACheck naCheck = NACheck.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(LoadFromConn2.class);
             casts.arg("con").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
             casts.arg("envir").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
             casts.arg("verbose").asLogicalVector().findFirst().map(toBoolean());
@@ -117,8 +116,8 @@ public class LoadSaveFunctions {
     public abstract static class Load extends RBuiltinNode {
         // now deprecated but still used by some packages
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Load.class);
             casts.arg("file").mustBe(stringValue()).asStringVector().mustBe(notEmpty(), RError.Message.FIRST_ARGUMENT_NOT_FILENAME).findFirst();
             casts.arg("envir").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
         }
@@ -194,10 +193,10 @@ public class LoadSaveFunctions {
         private static final String ASCII_HEADER = "RDA2\n";
         private static final String XDR_HEADER = "RDX2\n";
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SaveToConn.class);
             casts.arg("list").mustBe(stringValue()).asStringVector();
-            ConnectionFunctions.Casts.connection(casts);
+            ConnectionFunctions.CastsHelper.connection(casts);
             casts.arg("ascii").mustBe(logicalValue(), RError.Message.ASCII_NOT_LOGICAL);
             casts.arg("version").allowNull().mustBe(integerValue());
             casts.arg("environment").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LocaleFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LocaleFunctions.java
index 8e5625638866c182b9141f0437aa58b8aaadfb5f..29231259c8f30c438b3372b0a2074bc5bec39946 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LocaleFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LocaleFunctions.java
@@ -38,7 +38,7 @@ import java.nio.charset.Charset;
 
 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.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -55,9 +55,9 @@ public class LocaleFunctions {
     @RBuiltin(name = "Sys.getlocale", kind = INTERNAL, parameterNames = {"category"}, behavior = READS_STATE)
     public abstract static class GetLocale extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.category(casts);
+        static {
+            Casts casts = new Casts(GetLocale.class);
+            CastsHelper.category(casts);
         }
 
         @Specialization
@@ -93,9 +93,9 @@ public class LocaleFunctions {
     @RBuiltin(name = "Sys.setlocale", kind = INTERNAL, parameterNames = {"category", "locale"}, behavior = MODIFIES_STATE)
     public abstract static class SetLocale extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.category(casts);
+        static {
+            Casts casts = new Casts(SetLocale.class);
+            CastsHelper.category(casts);
             casts.arg("locale").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
         }
 
@@ -134,9 +134,10 @@ public class LocaleFunctions {
 
     @RBuiltin(name = "enc2native", kind = PRIMITIVE, parameterNames = "x", behavior = READS_STATE)
     public abstract static class Enc2Native extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.xCharacterVector(casts);
+
+        static {
+            Casts casts = new Casts(Enc2Native.class);
+            CastsHelper.xCharacterVector(casts);
         }
 
         @Specialization
@@ -148,9 +149,10 @@ public class LocaleFunctions {
 
     @RBuiltin(name = "enc2utf8", kind = PRIMITIVE, parameterNames = "x", behavior = READS_STATE)
     public abstract static class Enc2Utf8 extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.xCharacterVector(casts);
+
+        static {
+            Casts casts = new Casts(Enc2Utf8.class);
+            CastsHelper.xCharacterVector(casts);
         }
 
         @Specialization
@@ -162,8 +164,9 @@ public class LocaleFunctions {
 
     @RBuiltin(name = "bindtextdomain", kind = PRIMITIVE, parameterNames = {"domain", "dirname"}, behavior = READS_STATE)
     public abstract static class BindTextDomain extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(BindTextDomain.class);
             casts.arg("domain").mustBe(stringValue(), INVALID_VALUE, "domain");
         }
 
@@ -175,12 +178,12 @@ public class LocaleFunctions {
         }
     }
 
-    private static final class Casts {
-        private static void xCharacterVector(CastBuilder casts) {
+    private static final class CastsHelper {
+        private static void xCharacterVector(Casts casts) {
             casts.arg("x").mustBe(stringValue(), ARGUMENT_NOT_CHAR_VECTOR);
         }
 
-        private static void category(CastBuilder casts) {
+        private static void category(Casts casts) {
             casts.arg("category").mustBe(numericValue(), NO_CALLER, INVALID_ARGUMENT, "category").asIntegerVector().findFirst();
         }
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LogFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LogFunctions.java
index 457eca9da958eace8975e6ec36c6fb2cd25d90ca..e157019c8ea7564e0119b7875b9e47372a949452 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LogFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LogFunctions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,6 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -62,8 +61,8 @@ public class LogFunctions {
             return new Object[]{RMissing.instance, Math.E};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Log.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
             casts.arg("base").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue()).asDoubleVector().findFirst();
         }
@@ -141,8 +140,8 @@ public class LogFunctions {
 
         private static final double LOG_10 = Math.log(10);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Log10.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
@@ -168,8 +167,8 @@ public class LogFunctions {
 
         private static final double LOG_2 = Math.log(2);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Log2.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
@@ -193,8 +192,8 @@ public class LogFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Log1p.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ls.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ls.java
index aa4568846a3fcc0d798e8ef1ccb5e2efb9214e6a..0e05ca0385180b335d401f4dabb5fd5e165e474e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ls.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ls.java
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RStringVector;
@@ -39,8 +38,8 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 @RBuiltin(name = "ls", aliases = {"objects"}, kind = INTERNAL, parameterNames = {"envir", "all.names", "sorted"}, behavior = PURE)
 public abstract class Ls extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Ls.class);
         casts.arg("envir").mustBe(REnvironment.class, NO_CALLER, INVALID_ARGUMENT, "envir");
         casts.arg("all.names").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("sorted").asLogicalVector().findFirst().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 60c4ed1f56c3e6b0dcb6761445537868d2edd2b3..d1ac331fb5721d96bba15d982ce41211767f2174 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
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -46,8 +45,8 @@ public abstract class MakeNames extends RBuiltinNode {
     private final ConditionProfile namesLengthZero = ConditionProfile.createBinaryProfile();
     private final NACheck dummyCheck = NACheck.create(); // never triggered (used for vector update)
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(MakeNames.class);
         casts.arg("names").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.NON_CHARACTER_NAMES);
         casts.arg("allow_").defaultError(RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "allow_").asLogicalVector().findFirst().mustBe(notLogicalNA());
     }
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 452d330fa58c7b2469e5456a47cc2e3da7ff0006..9a0d72178e8784e0a2d6cf9ef82a6272f66e6b0a 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
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -45,8 +44,8 @@ public abstract class MakeUnique extends RBuiltinNode {
     private final ConditionProfile duplicatesProfile = ConditionProfile.createBinaryProfile();
     private final NACheck dummyCheck = NACheck.create(); // never triggered (used for vector update)
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(MakeUnique.class);
         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 2b0974310ba6da1362d10ffe6be67615acf1ac40..0eaf07b3d53e4ee843792d63ce03448234d71d16 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
@@ -36,7 +36,6 @@ import com.oracle.truffle.r.nodes.access.WriteVariableNode;
 import com.oracle.truffle.r.nodes.access.WriteVariableNode.Mode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.MapplyNodeGen.MapplyInternalNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.infix.Subscript;
@@ -67,8 +66,8 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 @RBuiltin(name = "mapply", kind = INTERNAL, parameterNames = {"FUN", "dots", "MoreArgs"}, splitCaller = true, behavior = COMPLEX)
 public abstract class Mapply extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Mapply.class);
         // let's assume that mapply internal is never called directly, otherwise all hell ensues -
         // even in GNU R .Internal(mapply(rep, 1:4, NULL)) causes a segfault
         casts.arg("FUN").mustBe(instanceOf(RFunction.class));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
index 7bee0fa552fc045332ea15babf8bdaa0daca15f6..88b10299f854ef5895632bc713867b51b4b27706 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -84,6 +84,10 @@ public abstract class MatMult extends RBuiltinNode {
 
     private final NACheck na;
 
+    static {
+        Casts.noCasts(MatMult.class);
+    }
+
     public MatMult(boolean promoteDimNames) {
         this.promoteDimNames = promoteDimNames;
         this.na = NACheck.create();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java
index b950ea128f04fbab771e66aa9734749ec98aa9a0..291aad6c297e6276d231df73417c2083fb91badd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode;
 import com.oracle.truffle.r.nodes.helpers.RFactorNodes;
@@ -73,8 +72,8 @@ public abstract class Match extends RBuiltinNode {
     private final NACheck naCheck = NACheck.create();
     private final ConditionProfile bigTableProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Match.class);
         // TODO initially commented out because of use of scalars, the commented out version
         // converted to new cast pipelines API
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArg.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArg.java
index 52cd9569f1e16a4bb037cf0944d6fb33073c0661..170e79418089d9fad4aabc809aa050a0bbc45eae 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArg.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArg.java
@@ -65,6 +65,10 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 @RBuiltin(name = "match.arg", kind = SUBSTITUTE, parameterNames = {"arg", "choices", "several.ok"}, nonEvalArgs = {0}, behavior = COMPLEX)
 public abstract class MatchArg extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(MatchArg.class);
+    }
+
     @Override
     public Object[] getDefaultParameterValues() {
         return new Object[]{RMissing.instance, RMissing.instance, RRuntime.LOGICAL_FALSE};
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java
index 5c0e91996458f2afd60c10f6912cf29b3e0c5f1c..69cb73a3f14f1f5e8d862ff172407a8c3ef575dc 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java
@@ -37,7 +37,6 @@ import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.MatchFunNodeGen.MatchFunInternalNodeGen;
 import com.oracle.truffle.r.nodes.function.GetCallerFrameNode;
@@ -65,8 +64,8 @@ public abstract class MatchFun extends RBuiltinNode {
         return new Object[]{RMissing.instance, RRuntime.LOGICAL_TRUE};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(MatchFun.class);
         casts.arg("descend").asLogicalVector().findFirst().map(toBoolean());
     }
 
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 45ca370e1f58679ad502a6889f47e8f939f8b90d..90f7823259a653c13679dd74346ac6f428e2ee77 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
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -66,8 +65,8 @@ public abstract class Matrix extends RBuiltinNode {
         return (RAbstractVector) updateDimNames.executeRAbstractContainer(vector, o);
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Matrix.class);
         casts.arg("data").asVector().mustBe(instanceOf(RAbstractVector.class));
         casts.arg("nrow").asIntegerVector().findFirst(RError.Message.NON_NUMERIC_MATRIX_EXTENT);
         casts.arg("ncol").asIntegerVector().findFirst(RError.Message.NON_NUMERIC_MATRIX_EXTENT);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Max.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Max.java
index 8c8030262bf8c721bf9c490b8b904e1469509c7c..2e898cf52915435168f803976d8ac0e8abf10098 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Max.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Max.java
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode.ReduceSemantics;
@@ -48,8 +47,8 @@ public abstract class Max extends RBuiltinNode {
 
     @Child private UnaryArithmeticReduceNode reduce = UnaryArithmeticReduceNodeGen.create(semantics, BinaryArithmetic.MAX);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Max.class);
         casts.arg("na.rm").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java
index c0c491b677d2d3be59592d06eab2ffe3546cd04f..dc04a0b92877a108aaf3d35057386b54bf16a0c8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,6 +46,10 @@ public abstract class Mean extends RBuiltinNode {
     @Child private BinaryArithmetic add = BinaryArithmetic.ADD.createOperation();
     @Child private BinaryArithmetic div = BinaryArithmetic.DIV.createOperation();
 
+    static {
+        Casts.noCasts(Mean.class);
+    }
+
     @Specialization
     protected double mean(RAbstractDoubleVector x) {
         if (x.getLength() == 0) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Merge.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Merge.java
index cef620df871e6e3f8e62b05bdd1356ff770671c6..955e3d4b9f9ad3ef906e5495565cd5daa2596788 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Merge.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Merge.java
@@ -38,19 +38,19 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 @RBuiltin(name = "merge", kind = INTERNAL, parameterNames = {"xinds", "yinds", "all.x", "all.y"}, behavior = PURE)
 public abstract class Merge extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Merge.class);
         addIntegerCast(casts, "xinds");
         addIntegerCast(casts, "yinds");
         addLogicalCast(casts, "all.x");
         addLogicalCast(casts, "all.y");
     }
 
-    private static void addIntegerCast(CastBuilder casts, String name) {
+    private static void addIntegerCast(Casts casts, String name) {
         casts.arg(name).mustBe(integerValue()).asIntegerVector().mustBe(notEmpty());
     }
 
-    private static void addLogicalCast(CastBuilder casts, String name) {
+    private static void addLogicalCast(Casts casts, String name) {
         casts.arg(name).defaultError(INVALID_LOGICAL, "all.x").mustBe(numericValue()).asLogicalVector().findFirst().notNA().map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Min.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Min.java
index 926920a97f1390d96521ec65e73204b713fc9ea7..09b73c273d4219428e837d870bca7555e078fdb5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Min.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Min.java
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode.ReduceSemantics;
@@ -48,8 +47,8 @@ public abstract class Min extends RBuiltinNode {
 
     @Child private UnaryArithmeticReduceNode reduce = UnaryArithmeticReduceNodeGen.create(semantics, BinaryArithmetic.MIN);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Min.class);
         casts.arg("na.rm").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).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 c2faec1d69a4fca54a7103a68e8e3552c7ac485b..b55927dda5324e900eee919da7ca7562f329fb30 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,6 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAt
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -52,8 +51,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "nchar", kind = INTERNAL, parameterNames = {"x", "type", "allowNA", "keepNA"}, behavior = PURE)
 public abstract class NChar extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(NChar.class);
         casts.arg("x").allowNull().mapIf(integerValue(), asIntegerVector(), asStringVector(true, false, false));
         casts.arg("type").asStringVector().findFirst();
         casts.arg("allowNA").asLogicalVector().findFirst(RRuntime.LOGICAL_TRUE).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 3756b5ba7cf1637a6a183d0d96331197eb16154c..147a3938761cdcf7a9bdf4a79d91fd8db788d5f8 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,8 +38,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 @RBuiltin(name = "ngettext", kind = INTERNAL, parameterNames = {"n", "msg1", "msg2", "domain"}, behavior = COMPLEX)
 public abstract class NGetText extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(NGetText.class);
         casts.arg("n").asIntegerVector().findFirst().mustBe(gte0());
 
         casts.arg("msg1").defaultError(RError.Message.MUST_BE_STRING, "msg1").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 cd2f85f3ecb0632aef82f813b21100d7afb058cf..bfd884b2fb2ec7e60ffaf504df65c2517ab53d7d 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
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -39,8 +38,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "nzchar", kind = PRIMITIVE, parameterNames = {"x", "keepNA"}, behavior = PURE)
 public abstract class NZChar extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(NZChar.class);
         casts.arg("x").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/Names.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Names.java
index 55c50f76361cc2080b1c84120370207135a03ece..fa425d7e20852ac5a9966b3d2d9082a045706ad2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Names.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Names.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,8 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
+import com.oracle.truffle.r.nodes.unary.UnaryNotNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
@@ -44,6 +46,10 @@ public abstract class Names extends RBuiltinNode {
     private final ConditionProfile hasNames = ConditionProfile.createBinaryProfile();
     @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create();
 
+    static {
+        Casts.noCasts(Names.class);
+    }
+
     @Specialization
     protected Object getNames(RAbstractContainer container) {
         RStringVector names = getNames.getNames(container);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NamespaceFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NamespaceFunctions.java
index 2f170e5f6602f6e9a4a95863808fc56e438c5221..919e2805fb1763cb8d3b26e25d2d7f5b5ec6502f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NamespaceFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NamespaceFunctions.java
@@ -29,6 +29,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_STATE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
@@ -43,17 +44,18 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 
 public class NamespaceFunctions {
 
-    private static final class Casts {
-        private static void name(CastBuilder casts) {
+    private static final class CastsHelper {
+        private static void name(Casts casts) {
             casts.arg("name").mustBe(stringValue().or(instanceOf(RSymbol.class)));
         }
     }
 
     @RBuiltin(name = "getRegisteredNamespace", kind = INTERNAL, parameterNames = {"name"}, behavior = READS_STATE)
     public abstract static class GetRegisteredNamespace extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.name(casts);
+
+        static {
+            Casts casts = new Casts(GetRegisteredNamespace.class);
+            CastsHelper.name(casts);
         }
 
         @Specialization
@@ -79,9 +81,10 @@ public class NamespaceFunctions {
 
     @RBuiltin(name = "isRegisteredNamespace", kind = INTERNAL, parameterNames = {"name"}, behavior = READS_STATE)
     public abstract static class IsRegisteredNamespace extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.name(casts);
+
+        static {
+            Casts casts = new Casts(IsRegisteredNamespace.class);
+            CastsHelper.name(casts);
         }
 
         @Specialization
@@ -107,6 +110,11 @@ public class NamespaceFunctions {
 
     @RBuiltin(name = "isNamespaceEnv", kind = INTERNAL, parameterNames = {"env"}, behavior = PURE)
     public abstract static class IsNamespaceEnv extends RBuiltinNode {
+
+        static {
+            Casts.noCasts(IsNamespaceEnv.class);
+        }
+
         @Specialization
         protected byte doIsNamespaceEnv(REnvironment env) {
             return RRuntime.asLogical(env.isNamespaceEnv());
@@ -128,9 +136,10 @@ public class NamespaceFunctions {
 
     @RBuiltin(name = "registerNamespace", kind = INTERNAL, parameterNames = {"name", "env"}, behavior = MODIFIES_STATE)
     public abstract static class RegisterNamespace extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.name(casts);
+
+        static {
+            Casts casts = new Casts(RegisterNamespace.class);
+            CastsHelper.name(casts);
             casts.arg("env").mustBe(instanceOf(REnvironment.class));
         }
 
@@ -154,9 +163,10 @@ public class NamespaceFunctions {
 
     @RBuiltin(name = "unregisterNamespace", kind = INTERNAL, parameterNames = {"name"}, behavior = MODIFIES_STATE)
     public abstract static class UnregisterNamespace extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.name(casts);
+
+        static {
+            Casts casts = new Casts(UnregisterNamespace.class);
+            CastsHelper.name(casts);
         }
 
         @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NormalizePath.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NormalizePath.java
index 528fb50198c01634224630cfb5e8082016abbdf5..835eb027f59d1a5151cc2012a0e45205961daee0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NormalizePath.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NormalizePath.java
@@ -38,7 +38,6 @@ import java.nio.file.NoSuchFileException;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -54,8 +53,8 @@ public abstract class NormalizePath extends RBuiltinNode {
 
     private final ConditionProfile doesNotNeedToWork = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(NormalizePath.class);
         casts.arg("path").mustBe(stringValue(), NOT_CHARACTER_VECTOR, "path");
         casts.arg("winslash").defaultError(NOT_CHARACTER_VECTOR, "winslash").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst().mustBe(eq("/").or(eq("\\\\")).or(eq("\\")),
                         WRONG_WINSLASH);
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 887b5f16ddffcf1e00cbbf2c895078f4d0b2d013..26a9bc602f80816b142a1cc48a126f4931a60ad7 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
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -62,8 +61,8 @@ public class NumericalFunctions {
             super(RType.Integer, RError.Message.NON_NUMERIC_MATH, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Abs.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(numericValue().or(complexValue()));
         }
 
@@ -105,8 +104,8 @@ public class NumericalFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Re.class);
             casts.arg("z").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
@@ -148,8 +147,8 @@ public class NumericalFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Im.class);
             casts.arg("z").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
@@ -191,8 +190,8 @@ public class NumericalFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Conj.class);
             casts.arg("z").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
@@ -224,8 +223,8 @@ public class NumericalFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Mod.class);
             casts.arg("z").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
@@ -267,8 +266,8 @@ public class NumericalFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_MATH, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Sign.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue());
         }
 
@@ -295,8 +294,8 @@ public class NumericalFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_MATH, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Sqrt.class);
             casts.arg("x").defaultError(RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue().or(complexValue()));
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OnExit.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OnExit.java
index 3eb6440923f772d5c4ba513b9dda0b2723d8a656..7d3f43e6bb2a7d14564136f1652f7e328f962c3a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OnExit.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OnExit.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,6 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.FrameSlotNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RError;
@@ -66,8 +65,8 @@ public abstract class OnExit extends RBuiltinNode {
 
     private final BranchProfile invalidateProfile = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(OnExit.class);
         casts.arg("add").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
     }
 
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 3edeeca12f54968580af52923630e07ef930ebb2..cc56be1bf20ed386310a29862acca11d0e86f77c 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
@@ -37,7 +37,6 @@ import com.oracle.truffle.api.dsl.Fallback;
 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.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
@@ -65,6 +64,10 @@ public class OptionsFunctions {
 
         private final ConditionProfile argNameNull = ConditionProfile.createBinaryProfile();
 
+        static {
+            Casts.noCasts(Options.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected RList options(@SuppressWarnings("unused") RMissing x) {
@@ -191,8 +194,8 @@ public class OptionsFunctions {
     @RBuiltin(name = "getOption", kind = INTERNAL, parameterNames = "x", behavior = READS_STATE)
     public abstract static class GetOption extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(GetOption.class);
             casts.arg("x").defaultError(RError.SHOW_CALLER, RError.Message.MUST_BE_STRING, "x").mustBe(stringValue()).asStringVector().findFirst();
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java
index 1dde2ca238caaf365de383a0c59043638f1b6ea2..13d246bb06695b34f5661040159aa99ab0dc143e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java
@@ -30,7 +30,6 @@ import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RPrecedenceBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.OrderNodeGen.CmpNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.OrderNodeGen.IsAtomicNANodeGen;
@@ -149,8 +148,8 @@ public abstract class Order extends RPrecedenceBuiltinNode {
         return (RAbstractVector) castVector2.execute(value);
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Order.class);
         casts.arg("na.last").mustBe(numericValue(), INVALID_LOGICAL, "na.last").asLogicalVector().findFirst();
         casts.arg("decreasing").mustBe(numericValue(), INVALID_LOGICAL, "decreasing").asLogicalVector().findFirst().map(toBoolean());
     }
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 ad4cbd55f2405b4a34761c15835f1a5b45127e3f..55db842837ac8f3b41d9f6ae52666592b76d78dc 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -45,8 +44,8 @@ public abstract class PMatch extends RBuiltinNode {
 
     public abstract RIntVector execute(RAbstractStringVector x, RAbstractStringVector table, int nomatch, boolean duplicatesOk);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(PMatch.class);
         casts.arg("x").asStringVector();
         casts.arg("table").asStringVector();
         casts.arg("nomatch").mapNull(constant(RRuntime.INT_NA)).asIntegerVector();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMinMax.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMinMax.java
index 3dc425ca9cd3f1eb88f88c50847d5825fdde8b06..89f53b790c7bc721080ae4e4fba6ebdafcd52f11 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMinMax.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMinMax.java
@@ -35,7 +35,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.PMinMaxNodeGen.MultiElemStringHandlerNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
@@ -90,9 +89,11 @@ public abstract class PMinMax extends RBuiltinNode {
         this.op = factory.createOperation();
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("na.rm").defaultError(SHOW_CALLER, Message.INVALID_VALUE, "na.rm").mustBe(numericValue()).asLogicalVector().findFirst().mustBe(logicalNA().not()).map(toBoolean());
+    static final class PMinMaxCasts extends Casts {
+        PMinMaxCasts(Class<? extends PMinMax> extCls) {
+            super(extCls);
+            casts.arg("na.rm").defaultError(SHOW_CALLER, Message.INVALID_VALUE, "na.rm").mustBe(numericValue()).asLogicalVector().findFirst().mustBe(logicalNA().not()).map(toBoolean());
+        }
     }
 
     private byte handleString(Object[] argValues, boolean naRm, int offset, int ind, int maxLength, byte warning, Object data) {
@@ -346,6 +347,11 @@ public abstract class PMinMax extends RBuiltinNode {
             super(new ReduceSemantics(RRuntime.INT_MIN_VALUE, Double.NEGATIVE_INFINITY, false, RError.Message.NO_NONMISSING_MAX, RError.Message.NO_NONMISSING_MAX_NA, false, true),
                             BinaryArithmetic.MAX);
         }
+
+        static {
+            new PMinMaxCasts(PMax.class);
+        }
+
     }
 
     @RBuiltin(name = "pmin", kind = INTERNAL, parameterNames = {"na.rm", "..."}, behavior = PURE)
@@ -355,6 +361,11 @@ public abstract class PMinMax extends RBuiltinNode {
             super(new ReduceSemantics(RRuntime.INT_MAX_VALUE, Double.POSITIVE_INFINITY, false, RError.Message.NO_NONMISSING_MIN, RError.Message.NO_NONMISSING_MIN_NA, false, true),
                             BinaryArithmetic.MIN);
         }
+
+        static {
+            new PMinMaxCasts(PMin.class);
+        }
+
     }
 
     protected boolean isIntegerPrecedence(RArgsValuesAndNames args) {
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 dbf770424540a5cb49b56be358b679c016361c66..7d68d79d72c62b7324e6ea0b4dacfce6f3a08f96 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
@@ -36,7 +36,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
@@ -101,8 +100,8 @@ public abstract class Parse extends RBuiltinNode {
     @Child private SetFixedAttributeNode setWholeSrcRefAttrNode = SetFixedAttributeNode.create("wholeSrcref");
     @Child private SetFixedAttributeNode setSrcFileAttrNode = SetFixedAttributeNode.create("srcfile");
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Parse.class);
         // Note: string is captured by the R wrapper and transformed to a file, other types not
         casts.arg("conn").defaultError(MUST_BE_STRING_OR_CONNECTION, "file").mustNotBeNull().asIntegerVector().findFirst();
         casts.arg("n").asIntegerVector().findFirst(RRuntime.INT_NA).notNA(-1);
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 4c01c4204c2e5f19a75da56ee022eac21b550e73..edd0e1c7367f98d55dfd3eb3be33206fa38e9f95 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
@@ -73,8 +73,8 @@ public abstract class Paste extends RBuiltinNode {
     private final ConditionProfile isNotStringProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile hasNoClassProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Paste.class);
         casts.arg(0).mustBe(RAbstractListVector.class);
         casts.arg("sep").asStringVector().findFirst(Message.INVALID_SEPARATOR);
         casts.arg("collapse").allowNull().mustBe(stringValue()).asStringVector().findFirst();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste0.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste0.java
index ce0645cb656fc2b009720a90ac2d8d751b1a9f62..4b85eb3b4f54384139fd1ba2e4443d50432e2872 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste0.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste0.java
@@ -42,8 +42,8 @@ public abstract class Paste0 extends RBuiltinNode {
 
     @Child private Paste pasteNode = PasteNodeGen.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Paste0.class);
         casts.arg("list").mustBe(RList.class);
         casts.arg("collapse").allowNull().mustBe(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 640b323010095b81810560ba398ca39a4b9028ea..fe07eed30f65a47f88c8d9eb8c39e3d4ced3f71c 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -38,8 +37,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "path.expand", kind = INTERNAL, parameterNames = "path", behavior = IO)
 public abstract class PathExpand extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(PathExpand.class);
         casts.arg("path").mustBe(stringValue());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Pretty.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Pretty.java
index b1881322b5ec87bb91d8bdbf810a45cc9442b1bb..aa7eaefcc74362e768a04c08765ff762f4df2445 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Pretty.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Pretty.java
@@ -21,7 +21,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -36,8 +35,8 @@ public abstract class Pretty extends RBuiltinNode {
 
     private static final RStringVector NAMES = RDataFactory.createStringVector(new String[]{"l", "u", "n"}, RDataFactory.COMPLETE_VECTOR);
 
-    @Override
-    public void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Pretty.class);
         casts.arg("l").asDoubleVector().findFirst().mustBe(isFinite());
         casts.arg("u").asDoubleVector().findFirst().mustBe(isFinite());
         casts.arg("n").asIntegerVector().findFirst().notNA().mustBe(gte0());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Primitive.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Primitive.java
index e2edcc133deb36eb31c1bbe3f7ec71fd0edd42cb..0a6d792c11e56c01789697c7799bcb810f7efee4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Primitive.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Primitive.java
@@ -31,7 +31,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -45,8 +44,8 @@ public abstract class Primitive extends RBuiltinNode {
 
     private final BranchProfile errorProfile = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Primitive.class);
         casts.arg("name").defaultError(Message.STRING_ARGUMENT_REQUIRED).mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
     }
 
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 4e4786a07b180c8a30a8e3296b88cd642866b3df..e2d8b344dd409fd5d9ee8706834e6cc8e0d5c306 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
@@ -37,7 +37,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetClassAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.printer.PrintParameters;
 import com.oracle.truffle.r.nodes.builtin.base.printer.ValuePrinterNode;
@@ -60,8 +59,8 @@ public class PrintFunctions {
 
         @Child private ValuePrinterNode valuePrinter = new ValuePrinterNode();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(PrintDefault.class);
             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());
@@ -111,8 +110,8 @@ public class PrintFunctions {
 
         @Child private ValuePrinterNode valuePrinter = new ValuePrinterNode();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(PrintFunction.class);
             casts.arg("x").mustBe(instanceOf(RFunction.class));
 
             casts.arg("useSource").defaultError(RError.Message.INVALID_ARGUMENT, "useSource").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
index 8c3caafcc5fd2c0f40e07d253411d6b734cde53d..132a9648895544e951e370763858a77e5063bd4a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -32,6 +32,10 @@ public abstract class Prod extends RBuiltinNode {
 
     // TODO: handle multiple arguments, handle na.rm
 
+    static {
+        Casts.noCasts(Prod.class);
+    }
+
     @Override
     public Object[] getDefaultParameterValues() {
         return new Object[]{RArgsValuesAndNames.EMPTY, RRuntime.LOGICAL_FALSE};
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 ea915b22192fcb4eee919f78e8457045067f4183..319c2ec107b87f322a41f1df2dc86110942571b1 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
@@ -36,7 +36,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -78,9 +77,11 @@ public abstract class Quantifier extends RBuiltinNode {
         return new Object[]{RArgsValuesAndNames.EMPTY, RRuntime.LOGICAL_FALSE};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("na.rm").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
+    static final class QuantifierCasts extends Casts {
+        QuantifierCasts(Class<? extends Quantifier> extCls) {
+            super(extCls);
+            casts.arg("na.rm").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
+        }
     }
 
     private void createArgCast(int index) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java
index 30d73cb3be9603add4e504a2591c80907bbbffdc..4a3d93122cab344c22ab3bff41cd344f2787faa5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java
@@ -19,7 +19,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RCleanUp;
 import com.oracle.truffle.r.runtime.RError;
@@ -34,8 +33,8 @@ import com.oracle.truffle.r.runtime.data.RNull;
 @RBuiltin(name = "quit", visibility = OFF, kind = INTERNAL, parameterNames = {"save", "status", "runLast"}, behavior = COMPLEX)
 public abstract class Quit extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Quit.class);
         casts.arg("save").mustBe(stringValue(), RError.Message.QUIT_ASK).asStringVector().findFirst();
         casts.arg("status").asIntegerVector().findFirst();
         casts.arg("runLast").asLogicalVector().findFirst();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quote.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quote.java
index fbce580f57c064a18595c02f113634e42902b01e..98620c384f3b17e826ea6058afa2a3c7ace3a036 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quote.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quote.java
@@ -40,6 +40,10 @@ public abstract class Quote extends RBuiltinNode {
 
     protected static final int LIMIT = 3;
 
+    static {
+        Casts.noCasts(Quote.class);
+    }
+
     private final ConditionProfile shareableProfile = ConditionProfile.createBinaryProfile();
 
     public abstract Object execute(RPromise expr);
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 56eb613f4988953f0121e14a1349a012cc241d50..315f03279d911c82020ff0608d5c320dbc28f618 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -52,10 +52,10 @@ public class RNGFunctions {
     @RBuiltin(name = "set.seed", visibility = OFF, kind = INTERNAL, parameterNames = {"seed", "kind", "normal.kind"}, behavior = MODIFIES_STATE)
     public abstract static class SetSeed extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SetSeed.class);
             casts.arg("seed").allowNull().mustBe(numericValue(), SHOW_CALLER, SEED_NOT_VALID_INT).asIntegerVector().findFirst();
-            Casts.kindInteger(casts, "kind", INVALID_ARGUMENT, "kind");
+            CastsHelper.kindInteger(casts, "kind", INVALID_ARGUMENT, "kind");
             // TODO: implement normal.kind specializations with String
             casts.arg("normal.kind").allowNull().mustBe(anyValue().not(), UNIMPLEMENTED_TYPE_IN_FUNCTION, "String", "set.seed").mustBe(stringValue(), SHOW_CALLER, INVALID_NORMAL_TYPE_IN_RGNKIND);
         }
@@ -83,10 +83,10 @@ public class RNGFunctions {
     @RBuiltin(name = "RNGkind", kind = INTERNAL, parameterNames = {"kind", "normkind"}, behavior = MODIFIES_STATE)
     public abstract static class RNGkind extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.kindInteger(casts, "kind", INVALID_ARGUMENT, "kind");
-            Casts.kindInteger(casts, "normkind", INVALID_NORMAL_TYPE_IN_RGNKIND);
+        static {
+            Casts casts = new Casts(RNGkind.class);
+            CastsHelper.kindInteger(casts, "kind", INVALID_ARGUMENT, "kind");
+            CastsHelper.kindInteger(casts, "normkind", INVALID_NORMAL_TYPE_IN_RGNKIND);
         }
 
         @Specialization
@@ -102,8 +102,8 @@ public class RNGFunctions {
         }
     }
 
-    private static final class Casts {
-        public static void kindInteger(CastBuilder casts, String name, Message error, Object... messageArgs) {
+    private static final class CastsHelper {
+        public static void kindInteger(Casts casts, String name, Message error, Object... messageArgs) {
             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/Range.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java
index 41ed3f09e74ada92c8d449b1d1ca60bbdabdb4a7..72ab6ad5c7e4227fd90998c13f5f7ed3825a0e0f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode.ReduceSemantics;
@@ -53,8 +52,8 @@ public abstract class Range extends RBuiltinNode {
     @Child private UnaryArithmeticReduceNode minReduce = UnaryArithmeticReduceNodeGen.create(minSemantics, BinaryArithmetic.MIN);
     @Child private UnaryArithmeticReduceNode maxReduce = UnaryArithmeticReduceNodeGen.create(maxSemantics, BinaryArithmetic.MAX);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Range.class);
         casts.arg("na.rm").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("finite").asLogicalVector().findFirst().map(toBoolean());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rank.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rank.java
index 73efc9004d81b14deb28319850e3ad5705e8628a..16f4d02288df99cd558c9ce7b8f13234589980ba 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rank.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rank.java
@@ -34,7 +34,6 @@ import java.util.function.Function;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.OrderNodeGen.CmpNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.OrderNodeGen.OrderVector1NodeGen;
@@ -62,20 +61,17 @@ public abstract class Rank extends RBuiltinNode {
         MIN
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        // @formatter:off
+    static {
+        Casts casts = new Casts(Rank.class);
         Function<Object, Object> typeFunc = x -> x.getClass().getSimpleName();
         casts.arg("x").mustBe(abstractVectorValue(), SHOW_CALLER, UNIMPLEMENTED_TYPE_IN_GREATER, typeFunc).mustBe(not(rawValue()), SHOW_CALLER, RError.Message.RAW_SORT);
-        // Note: in the case of no long vector support, when given anything but integer as n, GnuR behaves as if n=1,
+        // Note: in the case of no long vector support, when given anything but integer as n, GnuR
+        // behaves as if n=1,
         // we allow ourselves to be bit inconsistent with GnuR in that.
-        casts.arg("len").defaultError(NO_CALLER, INVALID_VALUE, "length(xx)").mustBe(numericValue()).
-                asIntegerVector().
-                mustBe(notEmpty()).
-                findFirst().mustBe(intNA().not().and(gte0()));
-        // Note: we parse ties.methods in the Specialization anyway, so the validation of the value is there
+        casts.arg("len").defaultError(NO_CALLER, INVALID_VALUE, "length(xx)").mustBe(numericValue()).asIntegerVector().mustBe(notEmpty()).findFirst().mustBe(intNA().not().and(gte0()));
+        // Note: we parse ties.methods in the Specialization anyway, so the validation of the value
+        // is there
         casts.arg("ties.method").defaultError(NO_CALLER, INVALID_TIES_FOR_RANK).mustBe(stringValue()).asStringVector().findFirst();
-        // @formatter:on
     }
 
     private Order.OrderVector1Node initOrderVector1() {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java
index 3a5414d396c6ffa846dda211718eecbe2a92ac36..4278530d54041bc9d62b0e24d0dbe9e542fcd48b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java
@@ -35,7 +35,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -53,8 +52,8 @@ public class RawFunctions {
     @RBuiltin(name = "charToRaw", kind = INTERNAL, parameterNames = "x", behavior = PURE)
     public abstract static class CharToRaw extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(CharToRaw.class);
             casts.arg("x").defaultError(RError.Message.ARG_MUST_BE_CHARACTER_VECTOR_LENGTH_ONE).mustBe(stringValue()).asStringVector().mustBe(notEmpty());
         }
 
@@ -74,8 +73,9 @@ public class RawFunctions {
 
     @RBuiltin(name = "rawToChar", kind = INTERNAL, parameterNames = {"x", "multiple"}, behavior = PURE)
     public abstract static class RawToChar extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(RawToChar.class);
             casts.arg("x").mustBe(instanceOf(RAbstractRawVector.class), RError.SHOW_CALLER, RError.Message.ARGUMENT_MUST_BE_RAW_VECTOR, "x");
             casts.arg("multiple").defaultError(RError.Message.INVALID_LOGICAL).asLogicalVector().findFirst().notNA().map(toBoolean());
         }
@@ -107,8 +107,9 @@ public class RawFunctions {
 
     @RBuiltin(name = "rawShift", kind = INTERNAL, parameterNames = {"x", "n"}, behavior = PURE)
     public abstract static class RawShift extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(RawShift.class);
             casts.arg("x").mustBe(instanceOf(RAbstractRawVector.class), RError.SHOW_CALLER, RError.Message.ARGUMENT_MUST_BE_RAW_VECTOR, "x");
             casts.arg("n").defaultError(RError.Message.MUST_BE_SMALL_INT, "shift").asIntegerVector().findFirst().notNA().mustBe(gte(-8).and(lte(8)));
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java
index ec205c198a4bf9870dc143127a22bf4188ece51a..538a0d8c685b99f55f14cc98478b740dfb422e7e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -37,8 +36,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 @RBuiltin(name = "rawToBits", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
 public abstract class RawToBits extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(RawToBits.class);
         casts.arg("x").mustNotBeNull(RError.SHOW_CALLER, RError.Message.ARGUMENT_MUST_BE_RAW_VECTOR, "x").mustBe(Predef.rawValue(), RError.SHOW_CALLER,
                         RError.Message.ARGUMENT_MUST_BE_RAW_VECTOR, "x");
     }
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 f5723074288a2a5e1d6c23fe82a544559bf575e4..f0a6a895958d889f1a046f5a434d4b2354de71d0 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
@@ -35,7 +35,6 @@ import java.util.Set;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.DCF;
 import com.oracle.truffle.r.runtime.RError;
@@ -52,8 +51,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "readDCF", kind = INTERNAL, parameterNames = {"conn", "fields", "keepwhite"}, behavior = IO)
 public abstract class ReadDCF extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(ReadDCF.class);
         casts.arg("conn").defaultError(Message.INVALID_CONNECTION).asIntegerVector().findFirst();
         casts.arg("fields").mapNull(emptyStringVector()).asStringVector();
         casts.arg("keepwhite").mapNull(emptyStringVector()).asStringVector();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadREnviron.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadREnviron.java
index 4ee6dbbd2502a83640dfc8e70d59f4419f199da8..999f8ef7f3d99c854995c2714c0abe3a884d1d41 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadREnviron.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadREnviron.java
@@ -32,7 +32,6 @@ import java.io.IOException;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -42,8 +41,8 @@ import com.oracle.truffle.r.runtime.context.RContext;
 @RBuiltin(name = "readRenviron", visibility = OFF, kind = INTERNAL, parameterNames = "x", behavior = COMPLEX)
 public abstract class ReadREnviron extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(ReadREnviron.class);
         casts.arg("x").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.ARGUMENT_MUST_BE_STRING, "x").asStringVector().findFirst();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Readline.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Readline.java
index 41f4eb9edbf28b16507ff62062abc6b9f5758287..bc5411859c8e3aff340dd5a79000ae01c4e690ff 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Readline.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Readline.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.ConsoleHandler;
@@ -37,8 +36,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "readline", kind = INTERNAL, parameterNames = "prompt", behavior = IO)
 public abstract class Readline extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Readline.class);
         casts.arg("prompt").asStringVector().findFirst("");
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Recall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Recall.java
index 45abdb5dbbb1433c677095cb0d2c9e221329a32c..4c53575646846ef0baac6dcc1e11b3bb3532cc2a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Recall.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Recall.java
@@ -55,6 +55,10 @@ public abstract class Recall extends RBuiltinNode {
 
     @Child private RExplicitCallNode call = RExplicitCallNode.create();
 
+    static {
+        Casts.noCasts(Recall.class);
+    }
+
     @Specialization
     protected Object recall(VirtualFrame frame, @SuppressWarnings("unused") RArgsValuesAndNames args) {
         Frame cframe = callerFrame.execute(frame);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RegFinalizer.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RegFinalizer.java
index 079bd5fdcb2ea7fe4e1b73189f411c788b47d8c7..4703cc2b232534e3199c5fd0d657f590ed8220e0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RegFinalizer.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RegFinalizer.java
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -39,8 +38,9 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 
 @RBuiltin(name = "reg.finalizer", kind = INTERNAL, parameterNames = {"e", "f", "onexit"}, behavior = COMPLEX)
 public abstract class RegFinalizer extends RBuiltinNode {
-    @Override
-    protected void createCasts(CastBuilder casts) {
+
+    static {
+        Casts casts = new Casts(RegFinalizer.class);
         casts.arg("e").mustBe(instanceOf(REnvironment.class).or(instanceOf(RExternalPtr.class)), RError.Message.REG_FINALIZER_FIRST);
         casts.arg("f").mustBe(instanceOf(RFunction.class), RError.Message.REG_FINALIZER_SECOND);
         casts.arg("onexit").asLogicalVector().findFirst().notNA(RError.Message.REG_FINALIZER_THIRD).map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java
index e89c2645f46e5482347b24152fbff85318ef7c3a..5d1bd20567546186b848131e658d4c926d1c73c7 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,12 +26,12 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVect
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.intNA;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.typeName;
 import static com.oracle.truffle.r.runtime.RDispatch.INTERNAL_GENERIC;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import java.util.Arrays;
-import java.util.function.Function;
 
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
@@ -40,7 +40,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -48,7 +47,6 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
@@ -90,14 +88,9 @@ public abstract class Repeat extends RBuiltinNode {
         return new Object[]{RMissing.instance, 1, RRuntime.INT_NA, 1};
     }
 
-    private String argType(Object arg) {
-        return ((RTypedValue) arg).getRType().getName();
-    }
-
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        Function<Object, Object> argType = this::argType;
-        casts.arg("x").mustBe(abstractVectorValue(), RError.Message.ATTEMPT_TO_REPLICATE, argType);
+    static {
+        Casts casts = new Casts(Repeat.class);
+        casts.arg("x").mustBe(abstractVectorValue(), RError.Message.ATTEMPT_TO_REPLICATE, typeName());
         casts.arg("times").defaultError(RError.Message.INVALID_ARGUMENT, "times").mustNotBeNull().asIntegerVector();
         casts.arg("length.out").mustNotBeNull().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)));
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 5b8a41d269027f4b4408107f8a7f2fb47220de61..f376567eced2d4c06962cddf51c185e8bfc5813b 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
@@ -24,16 +24,15 @@ 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.notEmpty;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.typeName;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
-import java.util.function.Function;
 import java.util.function.IntFunction;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -44,7 +43,6 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RRawVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
@@ -58,14 +56,9 @@ public abstract class RepeatInternal extends RBuiltinNode {
     private final ConditionProfile timesOneProfile = ConditionProfile.createBinaryProfile();
     private final BranchProfile errorProfile = BranchProfile.create();
 
-    private String argType(Object arg) {
-        return ((RTypedValue) arg).getRType().getName();
-    }
-
-    @Override
-    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);
+    static {
+        Casts casts = new Casts(RepeatInternal.class);
+        casts.arg("x").mustBe(abstractVectorValue(), RError.SHOW_CALLER2, RError.Message.ATTEMPT_TO_REPLICATE, typeName());
         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");
     }
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 90886c168a12f65bf7daf7f2f143ac7ebde0c846..163552a82d386614439cc55202e6a534b3c5dabb 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
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -20,7 +20,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import java.util.Arrays;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -42,8 +41,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 @RBuiltin(name = "rep_len", kind = INTERNAL, parameterNames = {"x", "length.out"}, behavior = PURE)
 public abstract class RepeatLength extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(RepeatLength.class);
         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").defaultError(RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "length.out").mustNotBeNull().asIntegerVector().mustBe(size(1)).findFirst().mustBe(notIntNA());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java
index 7001a7a16851efaa3c8dc0f19d6f4382dba5a86c..4acc844bfcec491fbe1a02061c703f4b2a2eeec6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java
@@ -72,6 +72,17 @@ public abstract class Return extends RBuiltinNode {
         return arguments.length == 1 ? new ReturnSpecial(arguments[0]) : null;
     }
 
+    private final BranchProfile isPromiseEvalProfile = BranchProfile.create();
+
+    static {
+        Casts.noCasts(Return.class);
+    }
+
+    @Override
+    public Object[] getDefaultParameterValues() {
+        return new Object[]{RNull.instance};
+    }
+
     static ReturnException doReturn(VirtualFrame frame, Object value, BranchProfile isPromiseEvalProfile) {
         RCaller call = RArguments.getCall(frame);
         while (call.isPromise()) {
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 74eb30e05f18afe578d50382ab41fa390c7b1e91..544075d500a238cd222f6e3253fde3f2e613aa73 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,6 @@ import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RError;
@@ -59,8 +58,8 @@ public abstract class Rm extends RBuiltinNode {
 
     private final BranchProfile invalidateProfile = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Rm.class);
         casts.arg("list").mustBe(stringValue(), SHOW_CALLER, INVALID_FIRST_ARGUMENT);
         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/Round.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java
index 56ee8c1890af73d35e5cc719d22cf986453bde5f..13230809bec5a91311616381d6ef0776ef5aebfa 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -63,22 +62,13 @@ public abstract class Round extends RBuiltinNode {
         return new Object[]{RMissing.instance, 0};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        //@formatter:off
-        casts.arg("x").
-            defaultError(this, RError.Message.NON_NUMERIC_MATH).
-            mustBe(numericValue().or(complexValue()));
+    static {
+        Casts casts = new Casts(Round.class);
+        casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(numericValue().or(complexValue()));
 
         // TODO: this should also accept vectors
         // TODO: digits argument is rounded, not simply stripped off the decimal part
-        casts.arg("digits").
-            defaultError(this, RError.Message.NON_NUMERIC_MATH).
-            mustBe(numericValue().or(complexValue())).
-            asIntegerVector().
-            findFirst();
-
-        //@formatter:on
+        casts.arg("digits").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(numericValue().or(complexValue())).asIntegerVector().findFirst();
     }
 
     @Specialization
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 a24d5c11c2b0f209ac0ac614e69a5dd7f6f9a3ee..245edd7529a5d4e4ac7ee9eeb94e509599404dce 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
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -19,7 +19,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -30,8 +29,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 @RBuiltin(name = "row", kind = INTERNAL, parameterNames = {"dims"}, behavior = PURE)
 public abstract class Row extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Row.class);
         casts.arg("dims").defaultError(SHOW_CALLER, RError.Message.MATRIX_LIKE_REQUIRED, "row").mustBe(integerValue()).asIntegerVector().mustBe(size(2));
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowMeans.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowMeans.java
index dd72109980a9ce6bc16e31f436ce7f28737f10da..fc308351bf9b6e6695951169b4e6997652974865 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowMeans.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowMeans.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -21,8 +21,14 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 
 // Implements .rowMeans
+@SuppressWarnings("unused")
 @RBuiltin(name = "rowMeans", kind = INTERNAL, parameterNames = {"X", "m", "n", "na.rm"}, behavior = PURE)
 public abstract class RowMeans extends RowSumsBase {
+
+    static {
+        new ColSumsCasts(RowMeans.class);
+    }
+
     @Specialization
     protected RDoubleVector rowMeans(RAbstractDoubleVector x, int rowNum, int colNum, boolean naRm) {
         return accumulateRows(x, rowNum, colNum, naRm, RowMeans::getMean, (v, nacheck, i) -> v.getDataAt(i));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowSums.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowSums.java
index 4fe2545e4c6436b4c6f9f347c7f78c672880f687..7659e933c14eb41a10071f000d76ab8164dde69d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowSums.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowSums.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -20,8 +20,14 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 
+@SuppressWarnings("unused")
 @RBuiltin(name = "rowSums", kind = INTERNAL, parameterNames = {"X", "m", "n", "na.rm"}, behavior = PURE)
 public abstract class RowSums extends RowSumsBase {
+
+    static {
+        new ColSumsCasts(RowSums.class);
+    }
+
     @Specialization
     protected RDoubleVector rowSums(RAbstractDoubleVector x, int rowNum, int colNum, boolean naRm) {
         return accumulateRows(x, rowNum, colNum, naRm, (sum, cnt) -> sum, (v, nacheck, i) -> v.getDataAt(i));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowsumFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowsumFunctions.java
index 207312d8a64a1ec44f1c22307794fdccb5b51052..f476fd860de97627ffa34e21ee1fdb090a7bee96 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowsumFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowsumFunctions.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995, 1996  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1997-2015,  The R Core Team
- * Copyright (c) 2016, Oracle and/or its affiliates
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -24,7 +24,6 @@ import java.util.HashMap;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -51,8 +50,8 @@ public class RowsumFunctions {
         private final ConditionProfile typeProfile = ConditionProfile.createBinaryProfile();
         private final NACheck na = NACheck.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Rowsum.class);
             casts.arg("x").mustBe(integerValue().or(doubleValue()), RError.Message.ROWSUM_NON_NUMERIC);
 
             casts.arg("g").asVector();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/S3DispatchFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/S3DispatchFunctions.java
index fe0c2dcfdeb9a00ad2a338387495faa551340ffa..76766dbfcf461522ebdfe0526af8661222a63a6e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/S3DispatchFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/S3DispatchFunctions.java
@@ -101,6 +101,10 @@ public abstract class S3DispatchFunctions extends RBuiltinNode {
         private final ConditionProfile argMissingProfile = ConditionProfile.createBinaryProfile();
         private final ConditionProfile argsValueAndNamesProfile = ConditionProfile.createBinaryProfile();
 
+        static {
+            Casts.noCasts(UseMethod.class);
+        }
+
         protected UseMethod() {
             super(false);
         }
@@ -193,6 +197,10 @@ public abstract class S3DispatchFunctions extends RBuiltinNode {
         private final ValueProfile parameterSignatureProfile = ValueProfile.createIdentityProfile();
         private final ValueProfile suppliedParameterSignatureProfile = ValueProfile.createIdentityProfile();
 
+        static {
+            Casts.noCasts(NextMethod.class);
+        }
+
         protected NextMethod() {
             super(true);
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample.java
index 128290e690bcff627f93a4610a946e645ea84a35..961dd4dfee08e12bf3c80324ee90fcd0a5b6aee1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample.java
@@ -39,7 +39,6 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -54,24 +53,15 @@ import com.oracle.truffle.r.runtime.rng.RRNG;
 public abstract class Sample extends RBuiltinNode {
     private final ConditionProfile sampleSizeProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        // @formatter:off
-        casts.arg("x").defaultError(SHOW_CALLER, INVALID_FIRST_ARGUMENT).allowNull().
-                mustBe(integerValue().or(doubleValue())).notNA(SHOW_CALLER, VECTOR_SIZE_NA_NAN).
-                mapIf(doubleValue(), chain(asDoubleVector()).with(findFirst().doubleElement()).
-                        with(mustBe(isFinite(), SHOW_CALLER, VECTOR_SIZE_NA_NAN)).
-                        with(mustBe(lt(4.5e15), SHOW_CALLER, VECTOR_SIZE_TOO_LARGE)).end()).
-                asIntegerVector().findFirst().mustBe(gte0());
-        casts.arg("size").defaultError(SHOW_CALLER, INVALID_ARGUMENT, "size").
-                mustBe(integerValue().or(doubleValue()).or(stringValue())).
-                asIntegerVector().findFirst().
-                defaultError(SHOW_CALLER, INVALID_ARGUMENT, "size").
-                notNA().mustBe(gte0());
-        casts.arg("replace").mustBe(integerValue().or(doubleValue()).or(logicalValue())).
-                asLogicalVector().mustBe(singleElement()).findFirst().notNA().map(toBoolean());
+    static {
+        Casts casts = new Casts(Sample.class);
+        casts.arg("x").defaultError(SHOW_CALLER, INVALID_FIRST_ARGUMENT).allowNull().mustBe(integerValue().or(doubleValue())).notNA(SHOW_CALLER, VECTOR_SIZE_NA_NAN).mapIf(doubleValue(),
+                        chain(asDoubleVector()).with(findFirst().doubleElement()).with(mustBe(isFinite(), SHOW_CALLER, VECTOR_SIZE_NA_NAN)).with(
+                                        mustBe(lt(4.5e15), SHOW_CALLER, VECTOR_SIZE_TOO_LARGE)).end()).asIntegerVector().findFirst().mustBe(gte0());
+        casts.arg("size").defaultError(SHOW_CALLER, INVALID_ARGUMENT, "size").mustBe(integerValue().or(doubleValue()).or(stringValue())).asIntegerVector().findFirst().defaultError(SHOW_CALLER,
+                        INVALID_ARGUMENT, "size").notNA().mustBe(gte0());
+        casts.arg("replace").mustBe(integerValue().or(doubleValue()).or(logicalValue())).asLogicalVector().mustBe(singleElement()).findFirst().notNA().map(toBoolean());
         casts.arg("prob").asDoubleVector();
-        // @formatter:on
     }
 
     // Validation that correlates two or more argument values (note: positiveness of prob is checked
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample2.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample2.java
index 90fb10fe618aa91a43b4401f37b737a0aa444660..8b1ad3e4b693e339e09038e755dcb26eef53065f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample2.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample2.java
@@ -28,7 +28,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.Collections.NonRecursiveHashSetDouble;
 import com.oracle.truffle.r.runtime.Collections.NonRecursiveHashSetInt;
@@ -50,18 +49,12 @@ public abstract class Sample2 extends RBuiltinNode {
 
     private final BranchProfile errorProfile = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        // @formatter:off
-        casts.arg("x").defaultError(SHOW_CALLER, INVALID_FIRST_ARGUMENT).allowNull().
-                mustBe(integerValue().or(doubleValue())).notNA(SHOW_CALLER, INVALID_FIRST_ARGUMENT).
-                asDoubleVector().findFirst().mustBe(gte(0.0)).mustBe(isFinite());
-        casts.arg("size").defaultError(SHOW_CALLER, INVALID_ARGUMENT, "size").
-                mustBe(integerValue().or(doubleValue())).
-                asIntegerVector().findFirst().
-                defaultError(SHOW_CALLER, INVALID_ARGUMENT, "size").
-                notNA().mustBe(gte0());
-        // @formatter:on
+    static {
+        Casts casts = new Casts(Sample2.class);
+        casts.arg("x").defaultError(SHOW_CALLER, INVALID_FIRST_ARGUMENT).allowNull().mustBe(integerValue().or(doubleValue())).notNA(SHOW_CALLER,
+                        INVALID_FIRST_ARGUMENT).asDoubleVector().findFirst().mustBe(gte(0.0)).mustBe(isFinite());
+        casts.arg("size").defaultError(SHOW_CALLER, INVALID_ARGUMENT, "size").mustBe(integerValue().or(doubleValue())).asIntegerVector().findFirst().defaultError(SHOW_CALLER, INVALID_ARGUMENT,
+                        "size").notNA().mustBe(gte0());
     }
 
     @Specialization(guards = "x > MAX_INT")
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 86377c5a1a09d11f700faff80ddd8072a8617d71..d80ec47fd7af1df9e9f57671b3595dd49f450b64 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
@@ -32,7 +32,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastToVectorNode;
 import com.oracle.truffle.r.nodes.unary.CastToVectorNodeGen;
@@ -101,8 +100,8 @@ public abstract class Scan extends RBuiltinNode {
         boolean skipNull = false;
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Scan.class);
         casts.arg("file").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
 
         casts.arg("what").asVector();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqFunctions.java
index 6bb73698a3040ef610461f9b261e1c53d6fcafb6..01d918d11731e52295a205252a4f5a8b24c145a7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqFunctions.java
@@ -29,9 +29,11 @@ import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.library.utils.TypeConvert;
+import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetClassAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.base.SeqFunctions.SeqInt.IsIntegralNumericNode;
 import com.oracle.truffle.r.nodes.builtin.base.SeqFunctionsFactory.GetIntegralNumericNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.SeqFunctionsFactory.IsMissingOrNumericNodeGen;
@@ -330,6 +332,10 @@ public final class SeqFunctions {
     public abstract static class SeqAlong extends RBuiltinNode {
         @Child private ClassHierarchyNode classHierarchyNode = ClassHierarchyNode.create();
 
+        static {
+            Casts.noCasts(SeqAlong.class);
+        }
+
         @Specialization(guards = "!hasClass(value)")
         protected RIntSequence seq(VirtualFrame frame, Object value,
                         @Cached("create()") RLengthNode length) {
@@ -373,8 +379,8 @@ public final class SeqFunctions {
     @RBuiltin(name = "seq_len", kind = PRIMITIVE, parameterNames = {"length.out"}, behavior = PURE)
     public abstract static class SeqLen extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SeqLen.class);
             /*
              * This is slightly different than what GNU R does as it will report coercion warning
              * for: seq_len(c("7", "b")) GNU R (presumably) gets the first element before doing a
@@ -426,6 +432,10 @@ public final class SeqFunctions {
 
         private static final double FLT_EPSILON = 1.19209290e-7;
 
+        static {
+            Casts.noCasts(SeqInt.class);
+        }
+
         protected abstract Object execute(VirtualFrame frame, Object start, Object to, Object by, Object lengthOut, Object alongWith);
 
         protected SeqInt(boolean seqFastPath) {
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 6d18414e514e2ec1a328f15a042c1168d790e560..94ba8ac89eba68fb1539384bd1804c72014fa797 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
@@ -86,15 +86,16 @@ public class SerializeFunctions {
             }
         }
 
-        protected void connection(CastBuilder casts) {
+        protected static void connection(Casts casts) {
             casts.arg("con").mustBe(integerValue()).asIntegerVector().findFirst();
         }
     }
 
     @RBuiltin(name = "unserializeFromConn", kind = INTERNAL, parameterNames = {"con", "refhook"}, behavior = IO)
     public abstract static class UnserializeFromConn extends Adapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(UnserializeFromConn.class);
             connection(casts);
         }
 
@@ -112,8 +113,9 @@ public class SerializeFunctions {
 
     @RBuiltin(name = "serializeToConn", visibility = OFF, kind = INTERNAL, parameterNames = {"object", "con", "ascii", "version", "refhook"}, behavior = IO)
     public abstract static class SerializeToConn extends Adapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SerializeToConn.class);
             connection(casts);
             casts.arg("ascii").mustBe(logicalValue(), RError.Message.ASCII_NOT_LOGICAL);
             casts.arg("version").allowNull().mustBe(integerValue());
@@ -135,8 +137,9 @@ public class SerializeFunctions {
 
     @RBuiltin(name = "unserialize", kind = INTERNAL, parameterNames = {"con", "refhook"}, behavior = IO)
     public abstract static class Unserialize extends Adapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(Unserialize.class);
             casts.arg("con").defaultError(Message.INVALID_CONNECTION).mustBe(integerValue().or(rawValue())).mapIf(integerValue(),
                             asIntegerVector().setNext(findFirst().integerElement()));
         }
@@ -154,8 +157,9 @@ public class SerializeFunctions {
 
     @RBuiltin(name = "serialize", kind = INTERNAL, parameterNames = {"object", "con", "type", "version", "refhook"}, behavior = IO)
     public abstract static class Serialize extends Adapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(Serialize.class);
             casts.arg("con").allowNull().mustBe(integerValue()).asIntegerVector().findFirst();
             casts.arg("type").asIntegerVector().findFirst();
         }
@@ -175,8 +179,9 @@ public class SerializeFunctions {
 
     @RBuiltin(name = "serializeb", kind = INTERNAL, parameterNames = {"object", "con", "xdr", "version", "refhook"}, behavior = IO)
     public abstract static class SerializeB extends Adapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SerializeB.class);
             connection(casts);
             casts.arg("xdr").asLogicalVector().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 4fa28d6d07affa289ed98896b73d0fb2876685e2..49a67b4f48980a143aad02f3f03e8ec02e465df8 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
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.objects.AsS4;
 import com.oracle.truffle.r.nodes.objects.AsS4NodeGen;
@@ -45,8 +44,8 @@ public abstract class SetS4Object extends RBuiltinNode {
 
     @Child private AsS4 asS4 = AsS4NodeGen.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(SetS4Object.class);
         casts.arg("object").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"
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetTimeLimit.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetTimeLimit.java
index 12b685c970a6708c7cd4b4d6a25eafd7800575c5..1b89fd845d9dbf51868d1edbe4d16746ce729a44 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetTimeLimit.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetTimeLimit.java
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -36,8 +35,8 @@ import com.oracle.truffle.r.runtime.data.RNull;
 @RBuiltin(name = "setTimeLimit", kind = INTERNAL, parameterNames = {"cpu", "elapsed", "transient"}, visibility = OFF, behavior = COMPLEX)
 public abstract class SetTimeLimit extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(SetTimeLimit.class);
         casts.arg("cpu").asDoubleVector().findFirst();
         casts.arg("elapsed").asDoubleVector().findFirst();
         casts.arg("transient").asLogicalVector().findFirst().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Setwd.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Setwd.java
index dc905f1abfc369b303d658b087e620fc4c756eb8..4c4abf4a6babb76967a8375e9285be5cee6c26e3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Setwd.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Setwd.java
@@ -33,7 +33,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.Utils;
@@ -43,8 +42,8 @@ import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 @RBuiltin(name = "setwd", visibility = OFF, kind = INTERNAL, parameterNames = "path", behavior = IO)
 public abstract class Setwd extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Setwd.class);
         casts.arg("path").defaultError(SHOW_CALLER, CHAR_ARGUMENT).mustBe(stringValue()).asStringVector().mustBe(notEmpty()).findFirst();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ShortRowNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ShortRowNames.java
index 17a035de4a7ff78c82f6ecf809bc11439af6a064..eed5de7dd1ead62987cd2954a548cc3fbb369516 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ShortRowNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ShortRowNames.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.IntValueProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetRowNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -51,8 +50,8 @@ public abstract class ShortRowNames extends RBuiltinNode {
 
     @Child private GetRowNamesAttributeNode getRowNamesNode = GetRowNamesAttributeNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(ShortRowNames.class);
         casts.arg("type").asIntegerVector().findFirst().mustBe(gte0().and(lte(2)));
     }
 
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 6ec1fc1d5e8c7db52f187dcc8905b6e7ff09bc20..5c3afc71a88a397a4839c202e2362c4c5ed9fcb3 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
@@ -40,7 +40,6 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.CopyAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.CopyAttributesNodeGen;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -69,8 +68,8 @@ public abstract class Signif extends RBuiltinNode {
     private final BranchProfile identity = BranchProfile.create();
     private final ConditionProfile infProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Signif.class);
         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()
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SinkFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SinkFunctions.java
index 85ad64c74004607cd7a7f2bf5b1f70568635e2dc..9ae7473c5fd527622e26ee63b9dbc4cb88343566 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SinkFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SinkFunctions.java
@@ -32,7 +32,6 @@ import java.io.IOException;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -43,8 +42,9 @@ import com.oracle.truffle.r.runtime.data.RNull;
 public class SinkFunctions {
     @RBuiltin(name = "sink", visibility = OFF, kind = INTERNAL, parameterNames = {"file", "closeOnExit", "type", "split"}, behavior = IO)
     public abstract static class Sink extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(Sink.class);
             casts.arg("file").mustBe(integerValue()).asIntegerVector().findFirst();
             casts.arg("closeOnExit").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("type").asLogicalVector().findFirst().notNA().map(toBoolean());
@@ -78,8 +78,9 @@ public class SinkFunctions {
 
     @RBuiltin(name = "sink.number", kind = INTERNAL, parameterNames = {"type"}, behavior = IO)
     public abstract static class SinkNumber extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SinkNumber.class);
             casts.arg("type").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
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 a01de6f6adf4ce7bbb32da6971574256c68dbebf..b785bc5ddd4cfc6dc4d3d34e8c540c729dc1a3fb 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
@@ -24,7 +24,6 @@ import com.oracle.truffle.r.nodes.access.AccessSlotNode;
 import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.WrapArgumentNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -38,8 +37,8 @@ public abstract class Slot extends RBuiltinNode {
 
     @Child private AccessSlotNode accessSlotNode = AccessSlotNodeGen.create(true);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Slot.class);
         casts.arg(0).asAttributable(true, true, true);
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SortFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SortFunctions.java
index 85bd174365a0e2f180837ab14f89ac8161630549..14ab57ffcff53764f729f1cc8e3717b09a768600 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SortFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SortFunctions.java
@@ -60,12 +60,12 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 public class SortFunctions {
 
     private abstract static class Adapter extends RBuiltinNode {
-        protected static void addCastForX(CastBuilder castBuilder) {
-            castBuilder.arg("x").allowNull().mustBe(abstractVectorValue(), SHOW_CALLER, ONLY_ATOMIC_CAN_BE_SORTED);
+        protected static void addCastForX(Casts casts) {
+            casts.arg("x").allowNull().mustBe(abstractVectorValue(), SHOW_CALLER, ONLY_ATOMIC_CAN_BE_SORTED);
         }
 
-        protected static void addCastForDecreasing(CastBuilder castBuilder) {
-            castBuilder.arg("decreasing").defaultError(SHOW_CALLER, INVALID_LOGICAL, "decreasing").mustBe(numericValue()).asLogicalVector().findFirst().map(toBoolean());
+        protected static void addCastForDecreasing(Casts casts) {
+            casts.arg("decreasing").defaultError(SHOW_CALLER, INVALID_LOGICAL, "decreasing").mustBe(numericValue()).asLogicalVector().findFirst().map(toBoolean());
         }
 
         @TruffleBoundary
@@ -152,8 +152,8 @@ public class SortFunctions {
     @RBuiltin(name = "sort", kind = INTERNAL, parameterNames = {"x", "decreasing"}, behavior = PURE)
     public abstract static class Sort extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Sort.class);
             addCastForX(casts);
             addCastForDecreasing(casts);
         }
@@ -182,8 +182,8 @@ public class SortFunctions {
     @RBuiltin(name = "qsort", kind = INTERNAL, parameterNames = {"x", "decreasing"}, behavior = PURE)
     public abstract static class QSort extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(QSort.class);
             addCastForX(casts);
             addCastForDecreasing(casts);
         }
@@ -202,8 +202,8 @@ public class SortFunctions {
     @RBuiltin(name = "psort", kind = INTERNAL, parameterNames = {"x", "partial"}, behavior = PURE)
     public abstract static class PartialSort extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(PartialSort.class);
             addCastForX(casts);
         }
 
@@ -242,8 +242,8 @@ public class SortFunctions {
     public abstract static class RadixSort extends Adapter {
         @Child private Order orderNode = OrderNodeGen.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(RadixSort.class);
             casts.arg("na.last").asLogicalVector().findFirst();
             casts.arg("decreasing").mustBe(numericValue(), SHOW_CALLER, INVALID_LOGICAL, "decreasing").asLogicalVector();
             casts.arg("retgrp").asLogicalVector().findFirst().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java
index 196ccc3cfa67dbe2260bad263fb742c9522f5636..b43d2e7fc99f702010a8b8dc62359b7caa97faad 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java
@@ -58,6 +58,10 @@ public abstract class Split extends RBuiltinNode {
     private static final int INITIAL_SIZE = 5;
     private static final int SCALE_FACTOR = 2;
 
+    static {
+        Casts.noCasts(Split.class);
+    }
+
     public static class SplitTemplate {
         @SuppressWarnings("unused") private int[] collectResultsSize;
         @SuppressWarnings("unused") private int nLevels;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sprintf.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sprintf.java
index a18ee23a793b911520dc0b9359999da104b20040..1a47d84f964031ec045edef55899b04c91a727c1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sprintf.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sprintf.java
@@ -45,8 +45,13 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "sprintf", kind = INTERNAL, parameterNames = {"fmt", "..."}, behavior = PURE)
+
 public abstract class Sprintf extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(Sprintf.class);
+    }
+
     public abstract Object executeObject(String fmt, Object args);
 
     @Child private Sprintf sprintfRecursive;
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 a23e27aca508e3968d1a3bc66a9d0b36c729fb37..9ca4d012ee7ee4ffb39ff638f80dd06d19859e5c 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
@@ -32,10 +32,8 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyScalarNode;
-import com.oracle.truffle.r.nodes.function.ClassHierarchyScalarNodeGen;
 import com.oracle.truffle.r.nodes.objects.CollectGenericArgumentsNode;
 import com.oracle.truffle.r.nodes.objects.CollectGenericArgumentsNodeGen;
 import com.oracle.truffle.r.nodes.objects.DispatchGeneric;
@@ -68,7 +66,6 @@ public abstract class StandardGeneric extends RBuiltinNode {
     @Child private LocalReadVariableNode readSigARgs = LocalReadVariableNode.create(RRuntime.DOT_SIG_ARGS, true);
     @Child private CollectGenericArgumentsNode collectArgumentsNode;
     @Child private DispatchGeneric dispatchGeneric = DispatchGenericNodeGen.create();
-    @Child private ClassHierarchyScalarNode classNode;
 
     @Child private CastNode castIntScalar;
     @Child private CastNode castStringScalar;
@@ -80,19 +77,11 @@ public abstract class StandardGeneric extends RBuiltinNode {
     private final BranchProfile noGenFunFound = BranchProfile.create();
     private final ConditionProfile sameNamesProfile = ConditionProfile.createBinaryProfile();
 
-    private String argClass(Object arg) {
-        if (classNode == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            classNode = insert(ClassHierarchyScalarNodeGen.create());
-        }
-        return classNode.executeString(arg);
-    }
-
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(StandardGeneric.class);
         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;
+        Function<Object, Object> argClass = ClassHierarchyScalarNode::get;
         casts.arg("fdef").defaultError(RError.SHOW_CALLER, RError.Message.EXPECTED_GENERIC, argClass).allowMissing().asAttributable(true, true, true).mustBe(instanceOf(RFunction.class));
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StartsEndsWithFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StartsEndsWithFunctions.java
index 361eaeb24a56e85928d45bac0790fbf8e50c4635..ac22038d7d2c0a191a01a6ea47729d51d1b5e0f4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StartsEndsWithFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StartsEndsWithFunctions.java
@@ -38,7 +38,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public class StartsEndsWithFunctions {
-    private static class Casts {
+    private static class CastsHelper {
         private static void arg(CastBuilder casts, String name) {
             casts.arg(name).mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.NON_CHARACTER_OBJECTS).asStringVector();
         }
@@ -48,10 +48,12 @@ public class StartsEndsWithFunctions {
         private final NACheck naCheck = NACheck.create();
         private final ConditionProfile singlePrefixProfile = ConditionProfile.createBinaryProfile();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.arg(casts, "x");
-            Casts.arg(casts, "prefix");
+        static final class AdapterCasts extends Casts {
+            AdapterCasts(Class<? extends Adapter> extCls) {
+                super(extCls);
+                CastsHelper.arg(casts, "x");
+                CastsHelper.arg(casts, "prefix");
+            }
         }
 
         protected Object doIt(RAbstractStringVector xVec, RAbstractStringVector prefixVec, boolean startsWith) {
@@ -95,17 +97,28 @@ public class StartsEndsWithFunctions {
         }
     }
 
+    @SuppressWarnings("unused")
     @RBuiltin(name = "startsWith", kind = INTERNAL, parameterNames = {"x", "prefix"}, behavior = PURE)
     public abstract static class StartsWith extends Adapter {
+
+        static {
+            new AdapterCasts(StartsWith.class);
+        }
+
         @Specialization
         protected Object startsWith(RAbstractStringVector x, RAbstractStringVector prefix) {
             return doIt(x, prefix, true);
         }
     }
 
+    @SuppressWarnings("unused")
     @RBuiltin(name = "endsWith", kind = INTERNAL, parameterNames = {"x", "prefix"}, behavior = PURE)
     public abstract static class EndsWith extends Adapter {
 
+        static {
+            new AdapterCasts(EndsWith.class);
+        }
+
         @Specialization
         protected Object endsWith(RAbstractStringVector x, RAbstractStringVector prefix) {
             return doIt(x, prefix, false);
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 44e3885490df21a52a38b543ea10413679a2fa49..efb1ada9f48b86cc105facbdc6b621367404c7c2 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
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -38,8 +37,9 @@ import com.oracle.truffle.r.runtime.data.RNull;
 
 @RBuiltin(name = "stop", kind = INTERNAL, parameterNames = {"call", "message"}, behavior = COMPLEX)
 public abstract class Stop extends RBuiltinNode {
-    @Override
-    protected void createCasts(CastBuilder casts) {
+
+    static {
+        Casts casts = new Casts(Stop.class);
         casts.arg("call").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("message").allowNull().mustBe(stringValue()).asStringVector().mustBe(notEmpty(), RError.Message.INVALID_STRING_IN_STOP).findFirst();
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strrep.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strrep.java
index 42746aea682f166ace97507fa447cc4fc884eaaf..6710bae7b4cab953d06866004c5da948a3a14f21 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strrep.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strrep.java
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -42,8 +41,8 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public abstract class Strrep extends RBuiltinNode {
     private final NACheck naCheck = NACheck.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Strrep.class);
         casts.arg("x").asStringVector();
         casts.arg("times").asIntegerVector();
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtoi.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtoi.java
index ce5653198a3d926047cf1bafafbb16a6b17e4808..86e2c0b11b9505253434ebbe8d8cf6805ccf9219 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtoi.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtoi.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.PrimitiveValueProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -46,8 +45,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "strtoi", kind = INTERNAL, parameterNames = {"x", "base"}, behavior = PURE)
 public abstract class Strtoi extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Strtoi.class);
         casts.arg("x").mustBe(stringValue()).asStringVector();
         // base == 0 || (base >= 2 && base <= 36)
         casts.arg("base").mustBe(integerValue()).asIntegerVector().findFirst().mustBe(eq(0).or(gte(2).and(lte(36))));
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 fa27e232c3ef00046c3744d4419b77e1c5e39332..9fb1980325dc7f5fa7887cd8d9b6088efd8e4472 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
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2016, Oracle and/or its affiliates
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -23,7 +23,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.ToLowerOrUpper.StringMapNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -37,8 +36,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "strtrim", kind = INTERNAL, parameterNames = {"x", "width"}, behavior = PURE)
 public abstract class Strtrim extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Strtrim.class);
         casts.arg("x").defaultError(Message.REQUIRES_CHAR_VECTOR, "strtrim()").mustBe(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/Substitute.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substitute.java
index f6077ad1c69a944453c2c1ed3298e0555b525425..395271e222dbd22d65793354e36b294d7a923ae5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substitute.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substitute.java
@@ -47,6 +47,10 @@ public abstract class Substitute extends RBuiltinNode {
 
     @Child private Quote quote;
 
+    static {
+        Casts.noCasts(Substitute.class);
+    }
+
     @Specialization
     protected Object doSubstitute(VirtualFrame frame, RPromise expr, @SuppressWarnings("unused") RMissing envMissing) {
         return doSubstituteWithEnv(expr, REnvironment.frameToEnvironment(frame.materialize()));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substr.java
index eec79076483a486ef103eaa62fbfc9f3f9a28651..b55b50f9431765f56c66c64914e0a0e07c12b3ea 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substr.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -47,6 +47,10 @@ public abstract class Substr extends RBuiltinNode {
     private final BranchProfile everSeenIllegalRange = BranchProfile.create();
     private final ConditionProfile naIndexesProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(Substr.class);
+    }
+
     @SuppressWarnings("unused")
     @Specialization(guards = "emptyArg(arg)")
     protected RStringVector substrEmptyArg(VirtualFrame frame, RAbstractStringVector arg, RAbstractIntVector start, RAbstractIntVector stop) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java
index e0571ca49d4a8a6027c433502824f1c7b7128e32..b8a914baf11c67dbfe8b66755ee5d500272c3c6f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java
@@ -31,7 +31,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode;
@@ -59,8 +58,8 @@ public abstract class Sum extends RBuiltinNode {
 
     @Child private UnaryArithmeticReduceNode reduce = UnaryArithmeticReduceNodeGen.create(semantics, BinaryArithmetic.ADD);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Sum.class);
         casts.arg("na.rm").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Switch.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Switch.java
index 50ea531bd0b278783ad912f9f615f84edc33f1eb..d1af871ffb367e3cde17326d76c03714d445bfd7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Switch.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Switch.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -59,6 +59,10 @@ public abstract class Switch extends RBuiltinNode {
     private final BranchProfile notIntType = BranchProfile.create();
     private final ConditionProfile noAlternativesProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(Switch.class);
+    }
+
     @Specialization
     protected Object doSwitch(VirtualFrame frame, RAbstractStringVector x, RArgsValuesAndNames optionalArgs) {
         if (x.getLength() != 1) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java
index 4e845a663b43d772f5df41e0ecba7a17efdcc8f8..cc35e6facb3475aecbfbf0572f472696085adbb7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java
@@ -52,7 +52,6 @@ import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinPackages;
 import com.oracle.truffle.r.runtime.RArguments;
@@ -90,8 +89,8 @@ public class SysFunctions {
     public abstract static class SysGetenv extends RBuiltinNode {
         private final ConditionProfile zeroLengthProfile = ConditionProfile.createBinaryProfile();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SysGetenv.class);
             casts.arg("x").mustBe(stringValue(), RError.Message.ARGUMENT_WRONG_TYPE);
             casts.arg("unset").mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
         }
@@ -163,8 +162,9 @@ public class SysFunctions {
 
     @RBuiltin(name = "Sys.setenv", visibility = OFF, kind = INTERNAL, parameterNames = {"nm", "values"}, behavior = MODIFIES_STATE)
     public abstract static class SysSetEnv extends LoadNamespaceAdapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysSetEnv.class);
             casts.arg("nm").mustBe(stringValue(), RError.Message.ARGUMENT_WRONG_TYPE);
             casts.arg("values").mustBe(stringValue(), RError.Message.ARGUMENT_WRONG_TYPE);
         }
@@ -192,8 +192,9 @@ public class SysFunctions {
 
     @RBuiltin(name = "Sys.unsetenv", visibility = OFF, kind = INTERNAL, parameterNames = {"x"}, behavior = READS_STATE)
     public abstract static class SysUnSetEnv extends LoadNamespaceAdapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysUnSetEnv.class);
             casts.arg("x").mustBe(stringValue(), RError.Message.ARGUMENT_WRONG_TYPE);
         }
 
@@ -217,8 +218,9 @@ public class SysFunctions {
 
     @RBuiltin(name = "Sys.sleep", visibility = OFF, kind = INTERNAL, parameterNames = {"time"}, behavior = COMPLEX)
     public abstract static class SysSleep extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysSleep.class);
             casts.arg("time").asDoubleVector().findFirst().mustBe(gte(0.0).and(eq(Double.NaN).not()));
         }
 
@@ -247,8 +249,9 @@ public class SysFunctions {
      */
     @RBuiltin(name = "Sys.readlink", kind = INTERNAL, parameterNames = {"paths"}, behavior = IO)
     public abstract static class SysReadlink extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysReadlink.class);
             casts.arg("paths").mustBe(stringValue());
         }
 
@@ -289,8 +292,9 @@ public class SysFunctions {
 
     @RBuiltin(name = "Sys.chmod", visibility = OFF, kind = INTERNAL, parameterNames = {"paths", "octmode", "use_umask"}, behavior = IO)
     public abstract static class SysChmod extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysChmod.class);
             casts.arg("paths").mustBe(stringValue());
             casts.arg("octmode").asIntegerVector().mustBe(notEmpty(), RError.Message.MODE_LENGTH_ONE);
             casts.arg("use_umask").asLogicalVector().findFirst().notNA().map(toBoolean());
@@ -316,8 +320,9 @@ public class SysFunctions {
     // TODO implement
     @RBuiltin(name = "Sys.umask", visibility = CUSTOM, kind = INTERNAL, parameterNames = {"octmode"}, behavior = COMPLEX)
     public abstract static class SysUmask extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysUmask.class);
             casts.arg("octmode").asIntegerVector().findFirst();
         }
 
@@ -366,8 +371,9 @@ public class SysFunctions {
 
     @RBuiltin(name = "Sys.glob", kind = INTERNAL, parameterNames = {"paths", "dirmask"}, behavior = IO)
     public abstract static class SysGlob extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysGlob.class);
             casts.arg("paths").mustBe(stringValue()).asStringVector();
             casts.arg("dirmask").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
@@ -394,8 +400,9 @@ public class SysFunctions {
 
     @RBuiltin(name = "setFileTime", kind = INTERNAL, parameterNames = {"path", "time"}, visibility = OFF, behavior = IO)
     public abstract static class SysSetFileTime extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysSetFileTime.class);
             casts.arg("path").mustBe(stringValue()).asStringVector().findFirst();
             casts.arg("time").asIntegerVector().findFirst().notNA();
         }
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 f6ac5b31210db26838958d33ad7ecafc6cb2f19d..bbe48d983e50afa4cf6352fcb2e9c01ac3342efd 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
@@ -17,7 +17,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -31,8 +30,8 @@ public abstract class Tabulate extends RBuiltinNode {
 
     private final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Tabulate.class);
         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/TempFile.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempFile.java
index 1d365eb082516038eb1ddecddd036f6add06b110..2bb1e17c5c3b177e8234a19de9fb86254b74301a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempFile.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempFile.java
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.TempPathName;
@@ -42,8 +41,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "tempfile", kind = INTERNAL, parameterNames = {"pattern", "tempdir", "fileext"}, behavior = COMPLEX)
 public abstract class TempFile extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(TempFile.class);
         casts.arg("pattern").asVector().mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.INVALID_FILENAME_PATTERN).mustBe(notEmpty(), RError.SHOW_CALLER, RError.Message.NO, "pattern");
         casts.arg("tempdir").asVector().mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "tempdir").findFirst(RError.SHOW_CALLER, RError.Message.NO, "tempdir");
         casts.arg("fileext").asVector().mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.INVALID_FILE_EXT).mustBe(notEmpty(), RError.SHOW_CALLER, RError.Message.NO, "fileext");
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ToLowerOrUpper.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ToLowerOrUpper.java
index 31023607abacfbcd6dffea008880f47efebf75ec..92d3eb1c98b110834b76f3ca6de0c7dd5ab6df48 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ToLowerOrUpper.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ToLowerOrUpper.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,6 @@ import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNodeGen;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -95,8 +94,8 @@ public abstract class ToLowerOrUpper {
 
         @Child private StringMapNode mapNode = StringMapNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ToLower.class);
             casts.arg(0, "x").mustBe(stringValue()).asStringVector(true, true, true);
         }
 
@@ -121,8 +120,8 @@ public abstract class ToLowerOrUpper {
 
         @Child private StringMapNode mapNode = StringMapNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ToUpper.class);
             casts.arg(0, "x").mustBe(stringValue()).asStringVector(true, true, true);
         }
 
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 949cc82fbf9d7d7ce0289ff706f4156b40562628..6ea603fb467c1a0032320ea2261f99bedbb11350 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
@@ -44,7 +44,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.GetFunctionsFactory.GetNodeGen;
 import com.oracle.truffle.r.nodes.builtin.helpers.TraceHandling;
@@ -70,12 +69,12 @@ public class TraceFunctions {
     private abstract static class PrimTraceAdapter extends RBuiltinNode {
         @Child private GetFunctions.Get getNode;
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            // @formatter:off
-            casts.arg("what").mustBe(instanceOf(RFunction.class).or(stringValue()), SHOW_CALLER, Message.ARG_MUST_BE_FUNCTION).
-                    mapIf(stringValue(), chain(asStringVector()).with(findFirst().stringElement()).end());
-            // @formatter:on
+        static final class PrimTraceCasts extends Casts {
+            PrimTraceCasts(Class<? extends PrimTraceAdapter> extCls) {
+                super(extCls);
+                casts.arg("what").mustBe(instanceOf(RFunction.class).or(stringValue()), SHOW_CALLER, Message.ARG_MUST_BE_FUNCTION).mapIf(stringValue(),
+                                chain(asStringVector()).with(findFirst().stringElement()).end());
+            }
         }
 
         protected Object getFunction(VirtualFrame frame, String funcName) {
@@ -90,6 +89,10 @@ public class TraceFunctions {
     @RBuiltin(name = ".primTrace", visibility = OFF, kind = PRIMITIVE, parameterNames = "what", behavior = COMPLEX)
     public abstract static class PrimTrace extends PrimTraceAdapter {
 
+        static {
+            new PrimTraceCasts(PrimTrace.class);
+        }
+
         @Specialization
         protected RNull primTrace(VirtualFrame frame, RAbstractStringVector funcName) {
             return primTrace((RFunction) getFunction(frame, funcName.getDataAt(0)));
@@ -110,6 +113,10 @@ public class TraceFunctions {
     @RBuiltin(name = ".primUntrace", visibility = OFF, kind = PRIMITIVE, parameterNames = "what", behavior = COMPLEX)
     public abstract static class PrimUnTrace extends PrimTraceAdapter {
 
+        static {
+            new PrimTraceCasts(PrimUnTrace.class);
+        }
+
         @Specialization
         protected RNull primUnTrace(VirtualFrame frame, RAbstractStringVector funcName) {
             return primUnTrace((RFunction) getFunction(frame, funcName.getDataAt(0)));
@@ -127,6 +134,11 @@ public class TraceFunctions {
 
     @RBuiltin(name = "traceOnOff", kind = INTERNAL, parameterNames = "state", behavior = COMPLEX)
     public abstract static class TraceOnOff extends RBuiltinNode {
+
+        static {
+            Casts.noCasts(TraceOnOff.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected byte traceOnOff(byte state) {
@@ -220,8 +232,9 @@ public class TraceFunctions {
      */
     @RBuiltin(name = "tracemem", kind = PRIMITIVE, parameterNames = "x", behavior = COMPLEX)
     public abstract static class Tracemem extends TracememBase {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(Tracemem.class);
             casts.arg("x").mustNotBeNull(Message.TRACEMEM_NOT_NULL);
         }
 
@@ -242,8 +255,8 @@ public class TraceFunctions {
 
         @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Retracemem.class);
             casts.arg("previous").defaultError(Message.INVALID_ARGUMENT, "previous").allowNullAndMissing().mustBe(stringValue());
         }
 
@@ -281,6 +294,11 @@ public class TraceFunctions {
 
     @RBuiltin(name = "untracemem", kind = PRIMITIVE, visibility = OFF, parameterNames = "x", behavior = COMPLEX)
     public abstract static class Untracemem extends TracememBase {
+
+        static {
+            Casts.noCasts(Untracemem.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected RNull execute(Object x) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Traceback.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Traceback.java
index fca379d84142ae6ae0350162429fc636a0f311ba..4c75e21ae311d40cd313575f18a934798e8a30a8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Traceback.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Traceback.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -36,8 +35,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 @RBuiltin(name = "traceback", kind = INTERNAL, parameterNames = {"x"}, behavior = COMPLEX)
 public abstract class Traceback extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Traceback.class);
         casts.arg("x").mustBe(numericValue()).asIntegerVector().findFirst();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
index f264855e7e247876ee24c162f2442ead75a88a7b..f9c7bf4af7be07a22ab8a39d1f214ec0325b04e5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
@@ -65,6 +65,10 @@ public abstract class Transpose extends RBuiltinNode {
     @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
     @Child private GetDimAttributeNode getDimNode;
 
+    static {
+        Casts.noCasts(Transpose.class);
+    }
+
     public abstract Object execute(RAbstractVector o);
 
     @FunctionalInterface
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TrigExpFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TrigExpFunctions.java
index 21efb2c61f2f6a0184dfa5fb9533a81314a41570..9839f2e54c92dd1172cd6c1df3c1f38ca1ef2518 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TrigExpFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TrigExpFunctions.java
@@ -35,7 +35,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.TrigExpFunctionsFactory.AcosNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.TrigExpFunctionsFactory.AsinNodeGen;
@@ -495,8 +494,8 @@ public class TrigExpFunctions {
         private final NACheck yNACheck = NACheck.create();
         private final NACheck xNACheck = NACheck.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Atan2.class);
             casts.arg(0).mapIf(numericValue(), asDoubleVector());
             casts.arg(1).mapIf(numericValue(), asDoubleVector());
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Trunc.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Trunc.java
index 3d0e13e8a458fc6d6d11fbe93943b603e41c7ff3..759597b4bcf5180f1955d47e6d3bcb2041856261 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Trunc.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Trunc.java
@@ -31,7 +31,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode;
 import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNodeGen;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticNodeGen;
@@ -48,16 +47,10 @@ public abstract class Trunc extends RBuiltinNode {
     @Child private BoxPrimitiveNode boxPrimitive = BoxPrimitiveNodeGen.create();
     @Child private UnaryArithmeticNode trunc = UnaryArithmeticNodeGen.create(TRUNC, RError.Message.NON_NUMERIC_MATH, RType.Double);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        //@formatter:off
-        casts.arg("x").
-            defaultError(this, RError.Message.NON_NUMERIC_MATH).
-            mustNotBeNull().
-            mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).
-            mustBe(numericValue()).
-            asDoubleVector(true, true, true);
-        //@formatter:on
+    static {
+        Casts casts = new Casts(Trunc.class);
+        casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustNotBeNull().mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue()).asDoubleVector(true,
+                        true, true);
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Typeof.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Typeof.java
index 735a4bf0e9a60da03b744aec6d278dc7ad546c6f..1366ac09fab02734ec974acab00d35836b115e31 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Typeof.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Typeof.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,10 @@ public abstract class Typeof extends RBuiltinNode {
 
     @Child private TypeofNode typeofNode = TypeofNodeGen.create();
 
+    static {
+        Casts.noCasts(Typeof.class);
+    }
+
     @Specialization
     protected String typeof(Object obj) {
         return typeofNode.execute(obj).getName();
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 ce157c2c110817217c85d133a32152162899e786..04288a4970a4ee6953ef51996511f9d076172ed3 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
@@ -20,7 +20,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetClassAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.RemoveClassAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RAttributable;
@@ -34,8 +33,8 @@ public abstract class UnClass extends RBuiltinNode {
     private final BranchProfile objectProfile = BranchProfile.create();
     private final BranchProfile shareableProfile = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UnClass.class);
         casts.arg("x").asAttributable(true, true, true);
     }
 
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 b6b914319a456d10fc634e9251eeede68ade1c4b..56cad49e98b51266daf2922badc316f2ccd52ffd 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
@@ -34,7 +34,6 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.Collections.NonRecursiveHashSet;
 import com.oracle.truffle.r.runtime.Collections.NonRecursiveHashSetDouble;
@@ -70,8 +69,8 @@ public abstract class Unique extends RBuiltinNode {
 
     private final ConditionProfile bigProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Unique.class);
         // these are similar to those in DuplicatedFunctions.java
         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
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java
index 4c7d7f36efcf7a969d41eefcf88a8ca622979fc2..67b2bbd51707a4e5a18fa48104f2401aecb7404c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java
@@ -23,7 +23,6 @@ import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.UnlistNodeGen.RecursiveLengthNodeGen;
 import com.oracle.truffle.r.nodes.unary.PrecedenceNode;
@@ -50,8 +49,8 @@ public abstract class Unlist extends RBuiltinNode {
 
     // portions of the algorithm were transcribed from GNU R
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Unlist.class);
         casts.arg("recursive").asLogicalVector().findFirst(RRuntime.LOGICAL_TRUE).map(toBoolean());
         casts.arg("use.names").asLogicalVector().findFirst(RRuntime.LOGICAL_TRUE).map(toBoolean());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
index b9597aa685c6fe4128d91cabff1223d9c1ac45a3..a9d87f4e4978b08bb04873a4f85121f5632530ef 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
@@ -42,7 +42,6 @@ import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetRowNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.UpdateAttrNodeGen.InternStringNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
@@ -98,8 +97,8 @@ public abstract class UpdateAttr extends RBuiltinNode {
         }
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateAttr.class);
         // Note: cannot check 'attributability' easily because atomic values, e.g int, are not
         // RAttributable.
         casts.arg("x"); // disallows null
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
index da512cd39800e5bb57c739754fff0e15630783f2..b86a4da62ef07c288cc889c5695d9b743b3f0df3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
@@ -38,7 +38,6 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNames
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetRowNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNodeGen;
@@ -72,12 +71,12 @@ public abstract class UpdateAttributes extends RBuiltinNode {
     @Child private SetRowNamesAttributeNode setRowNamesNode;
     @Child private RemoveAttributeNode removeAttrNode;
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateAttributes.class);
         // Note: cannot check 'attributability' easily because atomic values, e.g int, are not
         // RAttributable.
         casts.arg("obj"); // by default disallows RNull
-        casts.arg("value").mustBe(nullValue().or(instanceOf(RList.class)), this, ATTRIBUTES_LIST_OR_NULL);
+        casts.arg("value").mustBe(nullValue().or(instanceOf(RList.class)), ATTRIBUTES_LIST_OR_NULL);
     }
 
     // it's OK for the following two methods to update attributes in-place as the container has been
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
index 120e4b10edc38a829c548feb782fa24f57a16d51..7fd8850a961d0376793af976ff8af21e38e979f4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
@@ -23,7 +23,6 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClass
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNode;
 import com.oracle.truffle.r.nodes.binary.CastTypeNode;
 import com.oracle.truffle.r.nodes.binary.CastTypeNodeGen;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNodeGen;
@@ -51,8 +50,8 @@ public abstract class UpdateClass extends RBuiltinNode {
     @Child private TypeofNode typeof;
     @Child private SetClassAttributeNode setClassAttrNode = SetClassAttributeNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateClass.class);
         casts.arg("x"); // disallows null
         casts.arg("value").asStringVector();
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDim.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDim.java
index d30e638139ad629645041ed73dab870e8b043753..867c09bfd9d94bd70f5967e5081c10ab2e3c58cd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDim.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDim.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.RemoveFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.opt.ReuseNonSharedNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -49,10 +48,10 @@ public abstract class UpdateDim extends RBuiltinNode {
 
     @Child private ReuseNonSharedNode reuse = ReuseNonSharedNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateDim.class);
         casts.arg("x"); // disallows null
-        casts.arg("value").allowNull().asIntegerVector().mustBe(notEmpty(), this, LENGTH_ZERO_DIM_INVALID);
+        casts.arg("value").allowNull().asIntegerVector().mustBe(notEmpty(), LENGTH_ZERO_DIM_INVALID);
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
index d521f8a0edbac77d286ce14594ef8e9fbfb7db73..439c1b4a24a87890249021686aca040f5b847443 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
@@ -55,6 +55,10 @@ public abstract class UpdateDimNames extends RBuiltinNode {
     @Child private CastStringNode castStringNode;
     @Child private CastToVectorNode castVectorNode;
 
+    static {
+        Casts.noCasts(UpdateDimNames.class);
+    }
+
     private Object castString(Object o) {
         if (castStringNode == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLength.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLength.java
index 840f1ea37e6ae0a5fa9048f5eea3b92ddd70f023..38199269d78caf344dda3e5852a7be155b2c1586 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLength.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLength.java
@@ -34,7 +34,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -43,15 +42,11 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 @RBuiltin(name = "length<-", kind = PRIMITIVE, parameterNames = {"x", "value"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
 public abstract class UpdateLength extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateLength.class);
         // Note: `length<-`(NULL, newLen) really works in GnuR unlike other update builtins
-        // @formatter:off
-        casts.arg("x").allowNull().mustBe(abstractVectorValue(), this, INVALID_UNNAMED_ARGUMENT);
-        casts.arg("value").defaultError(this, INVALID_UNNAMED_VALUE).
-                mustBe(integerValue().or(doubleValue()).or(stringValue())).
-                asIntegerVector().mustBe(singleElement()).findFirst();
-        // @formatter:on
+        casts.arg("x").allowNull().mustBe(abstractVectorValue(), INVALID_UNNAMED_ARGUMENT);
+        casts.arg("value").defaultError(INVALID_UNNAMED_VALUE).mustBe(integerValue().or(doubleValue()).or(stringValue())).asIntegerVector().mustBe(singleElement()).findFirst();
     }
 
     @SuppressWarnings("unused")
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLevels.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLevels.java
index 472dc7388aede531c59cf4a9ac9e43687ebaacab..fd018457e0b7ae7593f0fb9eda653088196bd516 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLevels.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLevels.java
@@ -19,7 +19,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.RemoveFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -32,8 +31,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 @RBuiltin(name = "levels<-", kind = PRIMITIVE, parameterNames = {"x", "value"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
 public abstract class UpdateLevels extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateLevels.class);
         casts.arg("value").allowNull().asVector(false);
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java
index 134470c264132a4450dd6cff633200d80d78115f..afefd3a53d9906356b15807444a5985e6a550171 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java
@@ -46,6 +46,10 @@ public abstract class UpdateNames extends RBuiltinNode {
 
     @Child private CastStringNode castStringNode;
 
+    static {
+        Casts.noCasts(UpdateNames.class);
+    }
+
     private Object castString(Object o) {
         if (castStringNode == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
index 02c1ab3e723189351e01281fc7714e35326c9270..0ba6831d05d0ce923b21cda2912c773c0c5c3679 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,6 +48,10 @@ public abstract class UpdateOldClass extends RBuiltinNode {
     @Child private CastStringNode castStringNode;
     @Child private SetClassAttributeNode setClassAttributeNode = SetClassAttributeNode.create();
 
+    static {
+        Casts.noCasts(UpdateOldClass.class);
+    }
+
     @Specialization(guards = "!isStringVector(className)")
     protected Object setOldClass(RAbstractContainer arg, RAbstractVector className) {
         if (className.getLength() == 0) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java
index e97872b6a2d4d30a9c3c4591836a1229c8fb11c1..42af29b00154e6f9d0d42356bbc46b7345efb9cf 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java
@@ -25,7 +25,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.UpdateSlotNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNodeGen;
@@ -56,8 +55,8 @@ public abstract class UpdateSlot extends RBuiltinNode {
     @Child private CallRFunctionNode checkAtAssignmentCall;
     private final ConditionProfile cached = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateSlot.class);
         casts.arg(0).asAttributable(true, true, true);
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
index 804b73b66704a390fa5dee5d937b25a7c650b76d..690118997285088d23f31997c41305f015ec98c4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -51,6 +51,10 @@ public abstract class UpdateStorageMode extends RBuiltinNode {
 
     private final BranchProfile errorProfile = BranchProfile.create();
 
+    static {
+        Casts.noCasts(UpdateStorageMode.class);
+    }
+
     @Specialization
     protected Object update(Object x, String value,
                     @Cached("create()") ArrayAttributeNode attrAttrAccess,
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSubstr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSubstr.java
index c6cb92740a5b200d81b1b70d47ac3bee7a5b673a..0211c6ed55c6a46ef7ae1af8074b720bb2ee6427 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSubstr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSubstr.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -50,6 +50,10 @@ public abstract class UpdateSubstr extends RBuiltinNode {
 
     private final BranchProfile everSeenIllegalRange = BranchProfile.create();
 
+    static {
+        Casts.noCasts(UpdateSubstr.class);
+    }
+
     private static boolean rangeOk(String x, int start, int stop) {
         return start <= stop && start > 0 && stop > 0 && start <= x.length() && stop <= x.length();
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Utf8ToInt.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Utf8ToInt.java
index c1ba6395b156a309c7a5619dd38cdb7cfe8f0a0f..50aa92742d8aacee4305eabf32f687c48a09d668 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Utf8ToInt.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Utf8ToInt.java
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -40,8 +39,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 @RBuiltin(name = "utf8ToInt", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
 public abstract class Utf8ToInt extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Utf8ToInt.class);
         casts.arg(0, "x").defaultError(RError.SHOW_CALLER, RError.Message.ARG_MUST_BE_CHARACTER_VECTOR_LENGTH_ONE, "x").mustBe(stringValue()).asStringVector().mustBe(notEmpty()).shouldBe(size(1),
                         RError.SHOW_CALLER, RError.Message.ARG_SHOULD_BE_CHARACTER_VECTOR_LENGTH_ONE).findFirst();
     }
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 83f99a9513a2e09bb32b33e7d754e008d0e4af4a..b8d5a7b81f9b56e90c119e76d0dbeefc6017d74d 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode;
-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;
 import com.oracle.truffle.r.nodes.builtin.base.LapplyNodeGen.LapplyInternalNodeGen;
@@ -95,8 +94,8 @@ public abstract class VApply extends RBuiltinNode {
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
     @Child private SetNamesAttributeNode setNamesNode = SetNamesAttributeNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(VApply.class);
         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(),
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java
index 1cc2146e00887e850fb7d5cb9d3929145d837ff0..ee217670d4cccdd73e0fec37bba57a8401f459c6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java
@@ -31,7 +31,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNodeGen;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RType;
@@ -45,8 +44,8 @@ public abstract class Vector extends RBuiltinNode {
 
     @Child private TypeFromModeNode typeFromMode = TypeFromModeNodeGen.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Vector.class);
         casts.arg("mode").defaultError(RError.SHOW_CALLER, RError.Message.INVALID_ARGUMENT, "mode").asStringVector().mustBe(singleElement()).findFirst();
         casts.arg("length").defaultError(RError.SHOW_CALLER, RError.Message.INVALID_ARGUMENT, "length").asIntegerVector().mustBe(singleElement()).findFirst();
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Warning.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Warning.java
index bfb083d1593de793b7015cbe6c2e6a72882a1d0e..164019046ff4edb35b945d0888af84da8adf7d26 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Warning.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Warning.java
@@ -31,7 +31,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RErrorHandling;
@@ -40,8 +39,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 @RBuiltin(name = "warning", visibility = OFF, kind = INTERNAL, parameterNames = {"call", "immediate", "nobreaks", "message"}, behavior = COMPLEX)
 public abstract class Warning extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Warning.class);
         casts.arg("call").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("immediate").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("nobreaks").asLogicalVector().findFirst().map(toBoolean());
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 d61abdf172dc7771632649a18a52af47c9ca6123..7d0478eb4daa6ba146baad83c19c9eadf0404168 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
@@ -31,7 +31,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.WhichFunctionsFactory.WhichMaxNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.WhichFunctionsFactory.WhichMinNodeGen;
@@ -54,8 +53,8 @@ public class WhichFunctions {
     @RBuiltin(name = "which", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
     public abstract static class Which extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Which.class);
             casts.arg("x").mustBe(logicalValue()).asLogicalVector();
         }
 
@@ -111,9 +110,11 @@ public class WhichFunctions {
             this.isMax = isMax;
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg(0, "x").asDoubleVector(true, false, false);
+        static final class WhichMinMaxs extends Casts {
+            protected WhichMinMaxs(Class<? extends WhichMinMax> extCls) {
+                super(extCls);
+                casts.arg(0, "x").asDoubleVector(true, false, false);
+            }
         }
 
         @Specialization
@@ -156,6 +157,11 @@ public class WhichFunctions {
 
     @RBuiltin(name = "which.max", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
     public abstract static class WhichMax extends WhichMinMax {
+
+        static {
+            new WhichMinMaxs(WhichMax.class);
+        }
+
         protected WhichMax() {
             super(true);
         }
@@ -167,6 +173,11 @@ public class WhichFunctions {
 
     @RBuiltin(name = "which.min", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
     public abstract static class WhichMin extends WhichMinMax {
+
+        static {
+            new WhichMinMaxs(WhichMin.class);
+        }
+
         protected WhichMin() {
             super(false);
         }
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 5fb69cbcaa2880f35523e9f87043e8b8582771a3..fa52a36dfcb76e8a3c494bfadc59bedee2360544 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
@@ -92,6 +92,10 @@ public abstract class WithVisible extends RBuiltinNode {
         return RDataFactory.createList(new Object[]{value, RRuntime.asLogical(visibility.execute(frame))}, LISTNAMES);
     }
 
+    static {
+        Casts.noCasts(WithVisible.class);
+    }
+
     @Specialization
     protected RList withVisible(@SuppressWarnings("unused") RMissing x) {
         CompilerDirectives.transferToInterpreter();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java
index 1c8a3656ce594af08fe7f5997c7a2bc988764cb0..7d2c7fdfc68f94376451a5b07c2614759a4eb999 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,10 @@ public abstract class Xtfrm extends RBuiltinNode {
 
     @Child private GetFunctions.Get getNode;
 
+    static {
+        Casts.noCasts(Xtfrm.class);
+    }
+
     @Specialization
     protected Object xtfrm(VirtualFrame frame, Object x,
                     @Cached("createBinaryProfile()") ConditionProfile createProfile) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CairoProps.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CairoProps.java
index 5b13b78fd41c85a1360b40ba0b6770479ced4f90..4f9d28cfb20ff21248fc873b73113f5b7a46baf5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CairoProps.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CairoProps.java
@@ -5,22 +5,21 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
 package com.oracle.truffle.r.nodes.builtin.base.foreign;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 
 public abstract class CairoProps extends RExternalBuiltinNode.Arg1 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CairoProps.class);
         casts.arg(0).asIntegerVector();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
index 7acf32697d27496154580c1ef625c3cb9d935009..c8fc0b6df1d973f36b7631a6d93172e63cfd2c2c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
@@ -226,6 +226,10 @@ public class CallAndExternalFunctions {
 
         private final BranchProfile errorProfile = BranchProfile.create();
 
+        static {
+            Casts.noCasts(DotCall.class);
+        }
+
         @Override
         public Object[] getDefaultParameterValues() {
             return new Object[]{RMissing.instance, RArgsValuesAndNames.EMPTY, RMissing.instance};
@@ -723,6 +727,10 @@ public class CallAndExternalFunctions {
 
         private final BranchProfile errorProfile = BranchProfile.create();
 
+        static {
+            Casts.noCasts(DotExternal.class);
+        }
+
         @Override
         @TruffleBoundary
         protected RExternalBuiltinNode lookupBuiltin(RList f) {
@@ -821,6 +829,10 @@ public class CallAndExternalFunctions {
         private static final Object OP = "op";
         private static final Object RHO = "rho";
 
+        static {
+            Casts.noCasts(DotExternal2.class);
+        }
+
         private final BranchProfile errorProfile = BranchProfile.create();
 
         @Override
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrcf.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrcf.java
index 3ca0f0c97d0173a30490c3c5cdd8b0bf225426ec..6941258c6b612ed2902233fbe2d980d23a68585d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrcf.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrcf.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -30,6 +30,10 @@ public final class Dqrcf extends RExternalBuiltinNode {
     private static final String E = RRuntime.NAMES_ATTR_EMPTY_VALUE;
     private static final RStringVector DQRCF_NAMES = RDataFactory.createStringVector(new String[]{E, E, E, E, E, E, "coef", "info"}, RDataFactory.COMPLETE_VECTOR);
 
+    static {
+        Casts.noCasts(Dqrcf.class);
+    }
+
     @Override
     public RList call(RArgsValuesAndNames args) {
         Object[] argValues = args.getArguments();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrdc2.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrdc2.java
index e63b42dd1195018bf6b83324ff0ca72ef2dcdfb1..330ffbe41d6b285e2596c9d834ac3a9472d7a6ae 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrdc2.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrdc2.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -32,6 +32,10 @@ public final class Dqrdc2 extends RExternalBuiltinNode {
 
     @Child private GetDimAttributeNode getDimNode = GetDimAttributeNode.create();
 
+    static {
+        Casts.noCasts(Dqrdc2.class);
+    }
+
     @Override
     public RList call(RArgsValuesAndNames args) {
         Object[] argValues = args.getArguments();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Fft.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Fft.java
index 23bbc0cf05bdce9d6c73b4779a5010dc56034b37..aeb884a6112ddfb01ba9f6c767fd03a5ae12f1e5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Fft.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Fft.java
@@ -15,7 +15,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -28,8 +27,8 @@ public abstract class Fft extends RExternalBuiltinNode.Arg2 {
     private final ConditionProfile zVecLgt1 = ConditionProfile.createBinaryProfile();
     private final ConditionProfile noDims = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Fft.class);
         casts.arg(0).mustNotBeNull().asComplexVector(false, true, false);
         casts.arg(1).mustNotBeNull().asLogicalVector().findFirst().map(Predef.toBoolean());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Flushconsole.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Flushconsole.java
index 676a0d0deea140b9bf66bd076b2df41b1cd3d26e..6e7ef5004d895fc25a9935310cc6dbffed4193a1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Flushconsole.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Flushconsole.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -17,6 +17,10 @@ import com.oracle.truffle.r.runtime.data.RNull;
 
 public final class Flushconsole extends RExternalBuiltinNode {
 
+    static {
+        Casts.noCasts(Flushconsole.class);
+    }
+
     @Override
     public RNull call(RArgsValuesAndNames args) {
         return RNull.instance;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java
index 5bf8f743dbe2429af74dda69ba61190cc560643c..926aa8a2b34ec982e3ed3cba56962fe4538a704b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java
@@ -192,6 +192,10 @@ public class FortranAndCFunctions {
     @RBuiltin(name = ".Fortran", kind = PRIMITIVE, parameterNames = {".NAME", "...", "NAOK", "DUP", "PACKAGE", "ENCODING"}, behavior = COMPLEX)
     public abstract static class Fortran extends CRFFIAdapter {
 
+        static {
+            Casts.noCasts(Fortran.class);
+        }
+
         @Override
         @TruffleBoundary
         protected RExternalBuiltinNode lookupBuiltin(RList symbol) {
@@ -244,6 +248,10 @@ public class FortranAndCFunctions {
     @RBuiltin(name = ".C", kind = PRIMITIVE, parameterNames = {".NAME", "...", "NAOK", "DUP", "PACKAGE", "ENCODING"}, behavior = COMPLEX)
     public abstract static class DotC extends CRFFIAdapter {
 
+        static {
+            Casts.noCasts(DotC.class);
+        }
+
         @Override
         @TruffleBoundary
         protected RExternalBuiltinNode lookupBuiltin(RList symbol) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/LookupAdapter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/LookupAdapter.java
index c2ffbc4f9e5561b92eb6100884eeb58e4a5866ac..4f119f7a18d955d6c68694a0825f55211779d4b1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/LookupAdapter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/LookupAdapter.java
@@ -74,6 +74,10 @@ abstract class LookupAdapter extends RBuiltinNode {
     protected static class UnimplementedExternal extends RExternalBuiltinNode {
         private final String name;
 
+        static {
+            Casts.noCasts(UnimplementedExternal.class);
+        }
+
         public UnimplementedExternal(String name) {
             this.name = name;
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/MakeQuartzDefault.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/MakeQuartzDefault.java
index c0a8cbaffaee764c767a817b3f193b827affcfca..01f7905dfbab5f5baa4e2b64b5815845e64cfc32 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/MakeQuartzDefault.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/MakeQuartzDefault.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -17,6 +17,10 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 
 public final class MakeQuartzDefault extends RExternalBuiltinNode {
 
+    static {
+        Casts.noCasts(MakeQuartzDefault.class);
+    }
+
     @Override
     public Object call(RArgsValuesAndNames args) {
         return RRuntime.LOGICAL_FALSE;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ReadTableHead.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ReadTableHead.java
index e0c3cec0f8410e73c9d344af9bcbf2b0bc366971..71b34f14650b59a0124a88b485e15c153e94a17f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ReadTableHead.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ReadTableHead.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -15,7 +15,6 @@ import java.io.IOException;
 
 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.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -25,8 +24,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 public abstract class ReadTableHead extends RExternalBuiltinNode.Arg7 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(ReadTableHead.class);
         casts.arg(0).defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
         casts.arg(1).mustNotBeNull().asIntegerVector().findFirst();
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java
index 812d04235346fda7bcd8810c77989f2df34d5d1c..53cbadf9d42d75f9cc5fa5956c6511d145ff22f8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java
@@ -18,7 +18,6 @@ import java.io.IOException;
 
 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.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.printer.ComplexVectorPrinter;
@@ -50,8 +49,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public abstract class WriteTable extends RExternalBuiltinNode.Arg11 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(WriteTable.class);
         // file
         casts.arg(1).defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
         // nrows
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AccessField.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AccessField.java
index 8e3d1fcbe3a59acc02df303f37bf2cdeead03cb3..591c9236aa09c56baee7ac784bced4ca724aabf2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AccessField.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AccessField.java
@@ -39,7 +39,6 @@ import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
 import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
 import com.oracle.truffle.r.nodes.access.vector.ExtractListElement;
 import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RError;
@@ -95,8 +94,8 @@ public abstract class AccessField extends RBuiltinNode {
     private final ConditionProfile invalidAtomicVector = ConditionProfile.createBinaryProfile();
     private final BranchProfile error = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AccessField.class);
         casts.arg(1).defaultError(Message.INVALID_SUBSCRIPT_TYPE, RType.Language.getName()).mustBe(stringValue()).asStringVector().findFirst();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/ParenBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/ParenBuiltin.java
index a8655bf30d7bebc0b629f7f17af748376f1d30a5..08d6f1a6243c1359527a535f4e7d1eae0f508238 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/ParenBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/ParenBuiltin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,6 +52,10 @@ final class ParensSpecial extends RNode {
 @RBuiltin(name = "(", kind = PRIMITIVE, parameterNames = {""}, visibility = ON, behavior = PURE)
 public final class ParenBuiltin extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(ParenBuiltin.class);
+    }
+
     public static RNode special(ArgumentsSignature signature, RNode[] args, @SuppressWarnings("unused") boolean inReplacement) {
         if (signature == ArgumentsSignature.empty(1)) {
             return new ParensSpecial(args[0]);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subscript.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subscript.java
index 639d98960d7c6d646e830621a8926430c80d9136..176b95d29c7d08835e24a8acc0ab34b0cf7c7d8a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subscript.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subscript.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -190,6 +190,10 @@ public abstract class Subscript extends RBuiltinNode {
         // same implementation as "[[", with different dispatch
     }
 
+    static {
+        Casts.noCasts(Subscript.class);
+    }
+
     public static RNode special(ArgumentsSignature signature, RNode[] arguments, boolean inReplacement) {
         if (signature.getNonNullCount() == 0) {
             if (arguments.length == 2) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subset.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subset.java
index b36cbf5a3e24f4d056b0d5a8de2a166d631cd83d..82199ccb54e0f2d861beb07bba78376d41e3f74d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subset.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subset.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,6 @@ import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
 import com.oracle.truffle.r.nodes.access.vector.ExtractListElement;
 import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.infix.SpecialsUtils.ConvertIndex;
 import com.oracle.truffle.r.nodes.builtin.base.infix.SpecialsUtils.ProfiledValue;
@@ -136,8 +135,8 @@ public abstract class Subset extends RBuiltinNode {
 
     @Child private ExtractVectorNode extractNode = ExtractVectorNode.create(ElementAccessMode.SUBSET, false);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Subset.class);
         casts.arg("drop").asLogicalVector();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Tilde.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Tilde.java
index aa565195905cc4af852dcf237e0dfbf9e6d2adaf..5376735712f03ae5cba2f47de923ae1cd46b0f78 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Tilde.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Tilde.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -57,6 +57,10 @@ public abstract class Tilde extends RBuiltinNode {
 
     @Child private SetClassAttributeNode setClassAttrNode = SetClassAttributeNode.create();
 
+    static {
+        Casts.noCasts(Tilde.class);
+    }
+
     @Override
     public Object[] getDefaultParameterValues() {
         return new Object[]{RMissing.instance, RMissing.instance};
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateField.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateField.java
index b34a10d6215c19719005803f2836728ebd42e477..8723f67b6fa6bdc153df5f69d4b2b2b66bc0fbbb 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateField.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateField.java
@@ -38,7 +38,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
 import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
 import com.oracle.truffle.r.nodes.access.vector.ReplaceVectorNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode;
 import com.oracle.truffle.r.nodes.unary.CastListNode;
@@ -124,8 +123,8 @@ public abstract class UpdateField extends RBuiltinNode {
 
     private final ConditionProfile coerceList = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateField.class);
         casts.arg(1).defaultError(Message.INVALID_SUBSCRIPT).mustBe(stringValue()).asStringVector().findFirst();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubscript.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubscript.java
index 1488822ff52f5d2ecad17d08cfad470af6f3ad33..432d1c31a52325e64196631bab028e1ef0c15ca2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubscript.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubscript.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -165,6 +165,10 @@ public abstract class UpdateSubscript extends RBuiltinNode {
 
     private final ConditionProfile argsLengthLargerThanOneProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(UpdateSubscript.class);
+    }
+
     public static RNode special(ArgumentsSignature signature, RNode[] args, boolean inReplacement) {
         if (SpecialsUtils.isCorrectUpdateSignature(signature) && (args.length == 3 || args.length == 4)) {
             ProfiledValue vector = profile(args[0]);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubset.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubset.java
index 4e9fd8094a382c3eb0695c56baa8cce51cd91a4a..30ad8a85fcf3cd07e9c6cafed84b6744df555820 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubset.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubset.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -54,6 +54,10 @@ public abstract class UpdateSubset extends RBuiltinNode {
     @Child private ReplaceVectorNode replaceNode = ReplaceVectorNode.create(ElementAccessMode.SUBSET, false);
     private final ConditionProfile argsLengthLargerThanOneProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(UpdateSubset.class);
+    }
+
     public static RNode special(ArgumentsSignature signature, RNode[] args, boolean inReplacement) {
         if (SpecialsUtils.isCorrectUpdateSignature(signature) && (args.length == 3 || args.length == 4)) {
             ProfiledValue vector = profile(args[0]);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/system/SystemFunction.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/system/SystemFunction.java
index a045122de665406cca5d5bfd8055822a482bd2d2..ad08dd85ae9969918a2a38814598b27c7698c74c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/system/SystemFunction.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/system/SystemFunction.java
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -40,8 +39,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 public abstract class SystemFunction extends RBuiltinNode {
     @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(SystemFunction.class);
         casts.arg("command").mustBe(stringValue(), RError.Message.SYSTEM_CHAR_ARG).asStringVector().findFirst();
         casts.arg("intern").asLogicalVector().findFirst().notNA(RError.Message.SYSTEM_INTERN_NOT_NA).map(toBoolean());
     }
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 de95794b29df7c8fab0b73edfcef5d5aaf1ddec3..808039cbf19a215750a9f9f3fe47a5b5ce13d40f 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
@@ -37,7 +37,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.vm.PolyglotEngine;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RChannel;
 import com.oracle.truffle.r.runtime.RCmdOptions.Client;
@@ -62,25 +62,25 @@ public class FastRContext {
 
     private static final String[] EMPTY = new String[0];
 
-    private static final class Casts {
-        private static void exprs(CastBuilder casts) {
+    private static final class CastsHelper {
+        private static void exprs(Casts casts) {
             casts.arg("exprs").asStringVector().mustBe(notEmpty());
         }
 
-        private static void kind(CastBuilder casts) {
+        private static void kind(Casts casts) {
             casts.arg("kind").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst().notNA().mustBe(
                             equalTo(RContext.ContextKind.SHARE_NOTHING.name()).or(equalTo(RContext.ContextKind.SHARE_PARENT_RW.name()).or(equalTo(RContext.ContextKind.SHARE_PARENT_RO.name()))));
         }
 
-        private static void pc(CastBuilder casts) {
+        private static void pc(Casts casts) {
             casts.arg("pc").asIntegerVector().findFirst().notNA().mustBe(gt(0));
         }
 
-        private static void key(CastBuilder casts) {
+        private static void key(Casts casts) {
             casts.arg("key").asIntegerVector().mustBe(notEmpty()).findFirst();
         }
 
-        private static void id(CastBuilder casts) {
+        private static void id(Casts casts) {
             casts.arg("id").asIntegerVector().mustBe(notEmpty()).findFirst();
         }
     }
@@ -107,11 +107,11 @@ public class FastRContext {
             return new Object[]{RMissing.instance, 1, "SHARE_NOTHING"};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.exprs(casts);
-            Casts.pc(casts);
-            Casts.kind(casts);
+        static {
+            Casts casts = new Casts(Spawn.class);
+            CastsHelper.exprs(casts);
+            CastsHelper.pc(casts);
+            CastsHelper.kind(casts);
         }
 
         @Specialization
@@ -134,8 +134,9 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.context.join", visibility = OFF, kind = PRIMITIVE, parameterNames = {"handle"}, behavior = COMPLEX)
     public abstract static class Join extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(Join.class);
             casts.arg("handle").asIntegerVector().mustBe(notEmpty());
         }
 
@@ -178,11 +179,11 @@ public class FastRContext {
             return new Object[]{RMissing.instance, 1, "SHARE_NOTHING"};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.exprs(casts);
-            Casts.pc(casts);
-            Casts.kind(casts);
+        static {
+            Casts casts = new Casts(Eval.class);
+            CastsHelper.exprs(casts);
+            CastsHelper.pc(casts);
+            CastsHelper.kind(casts);
         }
 
         @Specialization
@@ -229,8 +230,8 @@ public class FastRContext {
             return new Object[]{RMissing.instance, RMissing.instance, RRuntime.LOGICAL_FALSE};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(R.class);
             casts.arg("args").allowMissing().mustBe(stringValue());
             casts.arg("env").allowMissing().mustBe(stringValue());
             casts.arg("intern").asLogicalVector().findFirst().map(toBoolean());
@@ -265,8 +266,8 @@ public class FastRContext {
             return new Object[]{RMissing.instance, RMissing.instance, RRuntime.LOGICAL_FALSE};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Rscript.class);
             casts.arg("args").mustBe(stringValue(), RError.Message.GENERIC, "usage: /path/to/Rscript [--options] [-e expr [-e expr2 ...] | file] [args]").asStringVector();
             casts.arg("env").allowMissing().mustBe(stringValue());
             casts.arg("intern").asLogicalVector().findFirst().map(toBoolean());
@@ -299,9 +300,9 @@ public class FastRContext {
     @RBuiltin(name = ".fastr.channel.create", kind = PRIMITIVE, parameterNames = {"key"}, behavior = COMPLEX)
     public abstract static class CreateChannel extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.key(casts);
+        static {
+            Casts casts = new Casts(CreateChannel.class);
+            CastsHelper.key(casts);
         }
 
         @Specialization
@@ -313,9 +314,10 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.channel.get", kind = PRIMITIVE, parameterNames = {"key"}, behavior = COMPLEX)
     public abstract static class GetChannel extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.key(casts);
+
+        static {
+            Casts casts = new Casts(GetChannel.class);
+            CastsHelper.key(casts);
         }
 
         @Specialization
@@ -327,9 +329,10 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.channel.close", visibility = OFF, kind = PRIMITIVE, parameterNames = {"id"}, behavior = COMPLEX)
     public abstract static class CloseChannel extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.id(casts);
+
+        static {
+            Casts casts = new Casts(CloseChannel.class);
+            CastsHelper.id(casts);
         }
 
         @Specialization
@@ -342,9 +345,10 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.channel.send", visibility = OFF, kind = PRIMITIVE, parameterNames = {"id", "data"}, behavior = COMPLEX)
     public abstract static class ChannelSend extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.id(casts);
+
+        static {
+            Casts casts = new Casts(ChannelSend.class);
+            CastsHelper.id(casts);
         }
 
         @Specialization
@@ -357,9 +361,10 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.channel.receive", kind = PRIMITIVE, parameterNames = {"id"}, behavior = COMPLEX)
     public abstract static class ChannelReceive extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.id(casts);
+
+        static {
+            Casts casts = new Casts(ChannelReceive.class);
+            CastsHelper.id(casts);
         }
 
         @Specialization
@@ -371,9 +376,10 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.channel.poll", kind = PRIMITIVE, parameterNames = {"id"}, behavior = COMPLEX)
     public abstract static class ChannelPoll extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.id(casts);
+
+        static {
+            Casts casts = new Casts(ChannelPoll.class);
+            CastsHelper.id(casts);
         }
 
         @Specialization
@@ -385,8 +391,9 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.channel.select", kind = PRIMITIVE, parameterNames = {"ids"}, behavior = COMPLEX)
     public abstract static class ChannelSelect extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(ChannelSelect.class);
             casts.arg("ids").mustBe(instanceOf(RList.class));
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRDebug.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRDebug.java
index e867b73ba1900ccd5040a1f346128a42fa1e48b5..6dd3870946dc0b52c010c7690ddbb329cab61706 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRDebug.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRDebug.java
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -38,8 +37,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = ".fastr.debug", visibility = OFF, kind = PRIMITIVE, parameterNames = {"values"}, behavior = COMPLEX)
 public abstract class FastRDebug extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FastRDebug.class);
         casts.arg("values").asStringVector();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java
index cb129360b7b21c4c5a513fab08d6850f4524f15a..5b76a6ac968905d6039b7e8c80a0707e08b4a6ca 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,10 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 @RBuiltin(name = ".fastr.identity", kind = PRIMITIVE, parameterNames = {""}, behavior = COMPLEX)
 public abstract class FastRIdentity extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(FastRIdentity.class);
+    }
+
     @Specialization
     @TruffleBoundary
     protected int typeof(Object x) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java
index 46df0267ccb8d55b0c25ca9521633de9f4fcccd0..d2cd4888e2b1df1307d8ffdfb04dc3ebbc666924 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java
@@ -48,7 +48,6 @@ import com.oracle.truffle.api.nodes.DirectCallNode;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.Source.Builder;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -66,8 +65,8 @@ public class FastRInterop {
     @RBuiltin(name = ".fastr.interop.eval", visibility = OFF, kind = PRIMITIVE, parameterNames = {"mimeType", "source"}, behavior = COMPLEX)
     public abstract static class Eval extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Eval.class);
             casts.arg("mimeType").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
             casts.arg("source").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
         }
@@ -106,8 +105,8 @@ public class FastRInterop {
     @RBuiltin(name = ".fastr.interop.evalFile", visibility = OFF, kind = PRIMITIVE, parameterNames = {"path", "mimeType"}, behavior = COMPLEX)
     public abstract static class EvalFile extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(EvalFile.class);
             casts.arg("path").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
             casts.arg("mimeType").allowMissing().mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
         }
@@ -146,8 +145,8 @@ public class FastRInterop {
     @RBuiltin(name = ".fastr.interop.export", visibility = OFF, kind = PRIMITIVE, parameterNames = {"name", "value"}, behavior = COMPLEX)
     public abstract static class Export extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Export.class);
             casts.arg("name").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
             casts.arg("value").boxPrimitive();
         }
@@ -178,8 +177,8 @@ public class FastRInterop {
     @RBuiltin(name = ".fastr.interop.import", visibility = OFF, kind = PRIMITIVE, parameterNames = {"name"}, behavior = COMPLEX)
     public abstract static class Import extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Import.class);
             casts.arg("name").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
         }
 
@@ -199,6 +198,10 @@ public class FastRInterop {
 
         @Child private Node node = com.oracle.truffle.api.interop.Message.HAS_SIZE.createNode();
 
+        static {
+            Casts.noCasts(HasSize.class);
+        }
+
         @Specialization
         public byte hasSize(VirtualFrame frame, TruffleObject obj) {
             return RRuntime.asLogical(ForeignAccess.sendHasSize(node, frame, obj));
@@ -210,6 +213,10 @@ public class FastRInterop {
 
         @Child private Node node = com.oracle.truffle.api.interop.Message.IS_NULL.createNode();
 
+        static {
+            Casts.noCasts(IsNull.class);
+        }
+
         @Specialization
         public byte hasSize(VirtualFrame frame, TruffleObject obj) {
             return RRuntime.asLogical(ForeignAccess.sendIsNull(node, frame, obj));
@@ -221,6 +228,10 @@ public class FastRInterop {
 
         @Child private Node node = com.oracle.truffle.api.interop.Message.IS_EXECUTABLE.createNode();
 
+        static {
+            Casts.noCasts(IsExecutable.class);
+        }
+
         @Specialization
         public byte hasSize(VirtualFrame frame, TruffleObject obj) {
             return RRuntime.asLogical(ForeignAccess.sendIsExecutable(node, frame, obj));
@@ -230,8 +241,8 @@ public class FastRInterop {
     @RBuiltin(name = ".fastr.interop.toBoolean", visibility = ON, kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX)
     public abstract static class ToBoolean extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ToBoolean.class);
             casts.arg("value").mustBe(logicalValue()).asLogicalVector().mustBe(singleElement()).findFirst().mustBe(notLogicalNA()).map(Predef.toBoolean());
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRPkgSource.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRPkgSource.java
index d072a3ad7688d02a242fa9763e46443b29037c8c..0306c6dc7a9167fbf5df2da024ede7f38acbe35f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRPkgSource.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRPkgSource.java
@@ -37,7 +37,6 @@ import java.nio.file.Path;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
@@ -70,8 +69,8 @@ public abstract class FastRPkgSource extends RBuiltinNode {
         return new Object[]{RNull.instance, RRuntime.LOGICAL_FALSE};
     }
 
-    @Override
-    public void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FastRPkgSource.class);
         casts.arg("pkgs").mustBe(stringValue());
         casts.arg("verbose").asLogicalVector().findFirst().notNA().map(toBoolean());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java
index 600608775cb0b6820c71684c03804b9c3453b466..a9e8cee05edafc523f5399c3ee63f76324ee33d0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,10 @@ import com.oracle.truffle.r.runtime.data.RShareable;
 @RBuiltin(name = ".fastr.refcountinfo", kind = PRIMITIVE, parameterNames = {""}, behavior = COMPLEX)
 public abstract class FastRRefCountInfo extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(FastRRefCountInfo.class);
+    }
+
     @Specialization
     protected int refcount(Object x) {
         if (x instanceof RShareable) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStackTrace.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStackTrace.java
index fbc559dc1a4a373de901ed544c2f28d9bc068a0b..f2b4d2b4d54af8bc4024cea49df6cf1b5b5b8679 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStackTrace.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStackTrace.java
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.Utils;
@@ -45,8 +44,8 @@ public abstract class FastRStackTrace extends RBuiltinNode {
         return new Object[]{RRuntime.LOGICAL_FALSE};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FastRStackTrace.class);
         casts.arg("print.frame.contents").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 dc521a05ffc1375c069d2b463954d8228e13d1cc..16abbd8f1637e254b177583593c0f21dabdc7cb0 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
@@ -42,7 +42,7 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -62,12 +62,12 @@ import com.oracle.truffle.tools.Profiler.Counter.TimeKind;
 
 public class FastRStats {
 
-    private static final class Casts {
-        private static void filename(CastBuilder casts) {
+    private static final class CastsHelper {
+        private static void filename(Casts casts) {
             casts.arg("filename").allowNull().mustBe(stringValue()).asStringVector();
         }
 
-        private static void append(CastBuilder casts) {
+        private static void append(Casts casts) {
             casts.arg("append").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).notNA().map(toBoolean());
         }
     }
@@ -79,10 +79,10 @@ public class FastRStats {
             return new Object[]{"Rprofattr.out", RRuntime.LOGICAL_FALSE};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.filename(casts);
-            Casts.append(casts);
+        static {
+            Casts casts = new Casts(FastRProfAttr.class);
+            CastsHelper.filename(casts);
+            CastsHelper.append(casts);
         }
 
         @SuppressWarnings("unused")
@@ -164,10 +164,10 @@ public class FastRStats {
             return new Object[]{"Rproftypecounts.out", RRuntime.LOGICAL_FALSE};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.filename(casts);
-            Casts.append(casts);
+        static {
+            Casts casts = new Casts(FastRProfTypecounts.class);
+            CastsHelper.filename(casts);
+            CastsHelper.append(casts);
         }
 
         @SuppressWarnings("unused")
@@ -295,10 +295,10 @@ public class FastRStats {
             return new Object[]{"Rproffuncounts.out", RRuntime.LOGICAL_FALSE, RRuntime.LOGICAL_FALSE, 0, RRuntime.LOGICAL_FALSE};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.filename(casts);
-            Casts.append(casts);
+        static {
+            Casts casts = new Casts(FastRProfFuncounts.class);
+            CastsHelper.filename(casts);
+            CastsHelper.append(casts);
             casts.arg("timing").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("threshold").asIntegerVector().findFirst().notNA();
             casts.arg("histograms").asLogicalVector().findFirst().notNA().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSyntaxTree.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSyntaxTree.java
index 580be8e81f89dc0d86ce4039640f9a6cd79abca6..8817ee3bcf7189734a8924abbc357265c6df5791 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSyntaxTree.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSyntaxTree.java
@@ -35,7 +35,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeVisitor;
 import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
 import com.oracle.truffle.r.nodes.instrumentation.RSyntaxTags;
@@ -74,8 +73,8 @@ public abstract class FastRSyntaxTree extends RBuiltinNode {
         return new Object[]{RMissing.instance, "syntaxelement", RRuntime.LOGICAL_FALSE, RRuntime.LOGICAL_FALSE};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FastRSyntaxTree.class);
         casts.arg("func").mustBe(instanceOf(RFunction.class));
         casts.arg("visitMode").asStringVector().findFirst();
         casts.arg("printSource").asLogicalVector().findFirst().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRThrowIt.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRThrowIt.java
index c24b8abdd4cc8a7d1f4a1b953ffb178fd0a94769..aa63c269457a97afd0f10107682f85fc22e5b6d5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRThrowIt.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRThrowIt.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 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.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.JumpToTopLevelException;
 import com.oracle.truffle.r.runtime.RError;
@@ -38,8 +37,9 @@ import com.oracle.truffle.r.runtime.data.RNull;
 
 @RBuiltin(name = ".fastr.throw", kind = PRIMITIVE, parameterNames = {"name"}, behavior = COMPLEX)
 public abstract class FastRThrowIt extends RBuiltinNode {
-    @Override
-    protected void createCasts(CastBuilder casts) {
+
+    static {
+        Casts casts = new Casts(FastRThrowIt.class);
         casts.arg("name").asStringVector().findFirst();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTrace.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTrace.java
index e2ead78ab4f671cb31cc1e16b71d9b7e9306a683..96eec41e231eac409ac72b9ed067e3c04168ada0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTrace.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTrace.java
@@ -115,6 +115,10 @@ public class FastRTrace {
         @Child private CastLogicalNode castLogical;
         @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
+        static {
+            Casts.noCasts(Trace.class);
+        }
+
         @Specialization
         protected Object trace(VirtualFrame frame, Object whatObj, Object tracer, Object exit, Object at, Object printObj, Object signature, Object whereObj) {
             Object what = whatObj;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTree.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTree.java
index 01682e5fbdd37758b76dae86366ea339ad2bc5b8..7071bb26a0b839e61a49f0997f1738cff88abfd1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTree.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTree.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.NodeUtil;
 import com.oracle.truffle.api.nodes.RootNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -46,8 +45,8 @@ public abstract class FastRTree extends RBuiltinNode {
         return new Object[]{RMissing.instance, RRuntime.LOGICAL_FALSE};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FastRTree.class);
         casts.arg("func").mustBe(instanceOf(RFunction.class));
         casts.arg("verbose").asLogicalVector().findFirst().map(toBoolean());
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTry.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTry.java
index 8ec98d89c9f19d0ee40082f4b122714b1a8b47af..45a57b19326df2fafe3f82f8218977900929712a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTry.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTry.java
@@ -44,6 +44,10 @@ import com.oracle.truffle.r.runtime.data.RFunction;
 public abstract class FastRTry extends RBuiltinNode {
     @Child private RExplicitCallNode call = RExplicitCallNode.create();
 
+    static {
+        Casts.noCasts(FastRTry.class);
+    }
+
     @Specialization
     public Object tryFunc(VirtualFrame frame, RFunction func) {
         try {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastrDqrls.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastrDqrls.java
index af534f63f7193b37fa2be279a455b17780eeb27c..fb4cc5a0b3a335acb99cdb2b2f0eb05b781063c2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastrDqrls.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastrDqrls.java
@@ -19,7 +19,6 @@ import java.util.Arrays;
 
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -43,8 +42,8 @@ public abstract class FastrDqrls extends RBuiltinNode {
     private static final String[] NAMES = new String[]{"qr", "coefficients", "residuals", "effects", "rank", "pivot", "qraux", "tol", "pivoted"};
     private static RStringVector namesVector = null;
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FastrDqrls.class);
         casts.arg("x").asDoubleVector(true, true, true);
         casts.arg("n").asIntegerVector().findFirst();
         casts.arg("p").asIntegerVector().findFirst();
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 531ad1205d1e9811eb1af45e321afa3df46a7c07..14bd470438b73db082a96dee6f152da748ca227b 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
@@ -28,6 +28,7 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asInteger;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asIntegerVector;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asLogicalVector;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asStringVector;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asVector;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.atomicIntegerValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.atomicLogicalValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.chain;
@@ -103,8 +104,11 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.env.REnvironment.NewEnv;
 
 /**
  * Tests the cast pipelines and also that the samples generation process matches the intended
@@ -121,6 +125,7 @@ public class CastBuilderTest {
     private static final boolean TEST_SAMPLING = false;
 
     private CastBuilder cb;
+    private CastNode castNode;
     private PreinitialPhaseBuilder arg;
 
     static {
@@ -135,6 +140,7 @@ public class CastBuilderTest {
     public void setUp() {
         cb = new CastBuilder(DummyBuiltin.class.getAnnotation(RBuiltin.class));
         arg = cb.arg("x");
+        castNode = null;
     }
 
     @After
@@ -488,6 +494,21 @@ public class CastBuilderTest {
         assertCastFail(RRuntime.INT_NA);
     }
 
+    @Test
+    public void testChain2() {
+        arg.
+        mapIf(instanceOf(RAbstractListVector.class),
+           chain(asVector()).
+              with(findFirst().objectElement()).
+              end()).mustBe(instanceOf(RList.class).or(instanceOf(REnvironment.class)));
+
+        RList l = RDataFactory.createList();
+        assertEquals(l, cast(RDataFactory.createList(new Object[]{l})));
+        NewEnv env = RDataFactory.createNewEnv("aaa");
+        assertEquals(env, cast(RDataFactory.createList(new Object[]{env})));
+        assertCastPreserves(env);
+    }
+
     public Function<InitialPhaseBuilder<Object>, InitialPhaseBuilder<Object>> nonListToBoolean() {
         return phaseBuilder -> phaseBuilder.
                         mapIf(instanceOf(RList.class).not(),
@@ -844,8 +865,7 @@ public class CastBuilderTest {
      * Casts given object using the configured pipeline in {@link #arg}.
      */
     private Object cast(Object a) {
-        CastNode argCastNode = cb.getCasts()[0];
-        NodeHandle<CastNode> argCastNodeHandle = TestUtilities.createHandle(argCastNode, (node, args) -> node.execute(args[0]));
+        NodeHandle<CastNode> argCastNodeHandle = TestUtilities.createHandle(getCastNode(), (node, args) -> node.execute(args[0]));
         return argCastNodeHandle.call(a);
     }
 
@@ -900,7 +920,7 @@ public class CastBuilderTest {
     }
 
     private TypeExpr resultTypes() {
-        CastNodeSampler<CastNode> sampler = CastNodeSampler.createSampler(cb.getCasts()[0]);
+        CastNodeSampler<CastNode> sampler = CastNodeSampler.createSampler(getCastNode());
         return sampler.resultTypes();
     }
 
@@ -909,7 +929,7 @@ public class CastBuilderTest {
             return;
         }
 
-        CastNodeSampler<CastNode> sampler = CastNodeSampler.createSampler(cb.getCasts()[0]);
+        CastNodeSampler<CastNode> sampler = CastNodeSampler.createSampler(getCastNode());
         Samples<?> samples = sampler.collectSamples();
         if (!emptyPositiveSamplesAllowed) {
             Assert.assertFalse(samples.positiveSamples().isEmpty());
@@ -917,6 +937,13 @@ public class CastBuilderTest {
         testPipeline(samples);
     }
 
+    private CastNode getCastNode() {
+        if (castNode == null) {
+            castNode = cb.getCasts()[0];
+        }
+        return castNode;
+    }
+
     private void testPipeline(Samples<?> samples) {
         if (!TEST_SAMPLING) {
             return;
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/PipelineToCastNodeTests.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/PipelineToCastNodeTests.java
index c74cd58b0759541c8de3efebd8863717d8ed3979..11c58387f483582624a1cb35361f476196d500de 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/PipelineToCastNodeTests.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/PipelineToCastNodeTests.java
@@ -25,6 +25,8 @@ package com.oracle.truffle.r.nodes.test;
 import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assert.assertEquals;
 
+import java.util.Optional;
+
 import org.junit.Test;
 
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter;
@@ -127,6 +129,6 @@ public class PipelineToCastNodeTests {
     private static CastNode createPipeline(PipelineStep<?, ?> lastStep) {
         PipelineConfigBuilder configBuilder = new PipelineConfigBuilder("x");
         configBuilder.setValueForwarding(false);
-        return PipelineToCastNode.convert(configBuilder.build(), lastStep);
+        return PipelineToCastNode.convert(configBuilder.build(), lastStep, Optional.empty());
     }
 }
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/RBuiltinDiagnostics.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/RBuiltinDiagnostics.java
index 62a2998e3dcf351e6402798ea5cdb4d8e60dc3c5..e4b307888c9c0fb6bcbc1bca72dd0b34c6a0d82d 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/RBuiltinDiagnostics.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/RBuiltinDiagnostics.java
@@ -94,6 +94,13 @@ public class RBuiltinDiagnostics {
     }
 
     public static void main(String[] args) throws Throwable {
+        // TODO: Enable it when the diagnostics is rewritten using CP-IR
+        if (true) {
+            System.out.println("Temporarily disabled until the diagnostics is rewritten using CP-IR");
+            return;
+        }
+
+        @SuppressWarnings("unused")
         RBuiltinDiagnostics rbDiag = ChimneySweepingSuite.createChimneySweepingSuite(args).orElseGet(() -> createRBuiltinDiagnostics(args));
 
         List<String> bNames = Arrays.stream(args).filter(arg -> !arg.startsWith("-")).collect(Collectors.toList());
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
index c1c544f7505e35960f5f405136a803c2277fab8f..cbf0003eecd8b8e5b9efc923888ecbf2d9be2c6a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
@@ -29,7 +29,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ValueProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.primitive.BinaryMapNode;
 import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode;
@@ -67,8 +66,8 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode {
         this.unary = unaryFactory;
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(BinaryArithmeticNode.class);
         casts.arg(0).boxPrimitive();
         casts.arg(1).boxPrimitive();
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
index 1ce1356f4f03fa04a98eb9d9711924fa9c5d031d..6983da07a46caf6f967b9546b66b97ee1220a500 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
@@ -28,7 +28,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.primitive.BinaryMapNode;
 import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode;
@@ -67,8 +66,8 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
         this.factory = factory;
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(BinaryBooleanNode.class);
         casts.arg(0).boxPrimitive();
         casts.arg(1).boxPrimitive();
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java
index 742f104bcbfec3f612766ad1ee0be1b8ceb9c3df..3026310ff21bd27440abc320c7cb1fd058d55a31 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java
@@ -62,6 +62,10 @@ public abstract class BinaryBooleanScalarNode extends RBuiltinNode {
 
     private final BooleanOperation booleanLogic;
 
+    static {
+        Casts.noCasts(BinaryBooleanScalarNode.class);
+    }
+
     BinaryBooleanScalarNode(BooleanOperationFactory factory) {
         this.booleanLogic = factory.createOperation();
         logic = new BinaryMapBooleanFunctionNode(booleanLogic);
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 8ad506b96d2ee1845d9467453622d1380145c375..4d4279b45d537e5e58ad13fd35aec0d17e0b1266 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
@@ -91,7 +91,6 @@ public final class CastBuilder {
     private final RBuiltin builtin;
     private final String[] argumentNames;
     private PipelineBuilder[] argumentBuilders;
-    private CastNode[] castsCache = null;
 
     public CastBuilder(RBuiltin builtin) {
         // Note: if we have the builtin metadata, we pre-allocate the arrays, builtinNode != null is
@@ -125,16 +124,14 @@ public final class CastBuilder {
      * casting, returns {@code null} as its cast node.
      */
     public CastNode[] getCasts() {
-        if (castsCache == null) {
-            castsCache = new CastNode[argumentBuilders.length];
-            for (int i = 0; i < argumentBuilders.length; i++) {
-                PipelineBuilder arg = argumentBuilders[i];
-                if (arg != null) {
-                    castsCache[i] = arg.buildNode();
-                }
+        CastNode[] castNodes = new CastNode[argumentBuilders.length];
+        for (int i = 0; i < argumentBuilders.length; i++) {
+            PipelineBuilder arg = argumentBuilders[i];
+            if (arg != null) {
+                castNodes[i] = arg.buildNode();
             }
         }
-        return castsCache;
+        return castNodes;
     }
 
     // ---------------------
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/NodeWithArgumentCasts.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/NodeWithArgumentCasts.java
new file mode 100644
index 0000000000000000000000000000000000000000..01a7e12b531c71198c49d70b8655ed36e5be9f24
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/NodeWithArgumentCasts.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.oracle.truffle.api.dsl.GeneratedBy;
+import com.oracle.truffle.r.nodes.builtin.casts.fluent.PreinitialPhaseBuilder;
+import com.oracle.truffle.r.nodes.unary.CastNode;
+import com.oracle.truffle.r.nodes.unary.UnaryArithmeticBuiltinNode;
+import com.oracle.truffle.r.runtime.builtins.RBuiltin;
+
+public interface NodeWithArgumentCasts {
+
+    default Casts getCastHolder() {
+        Class<?> cls = Casts.getBuiltinClass(getClass());
+        Casts casts = Casts.forClass(cls);
+        assert casts != null || Casts.noCastsAllowed(getClass().getSuperclass()) : "No casts associated with builtin " + cls;
+        return casts == null ? Casts.empty : casts;
+    }
+
+    default CastNode[] getCasts() {
+        CastNode[] casts = getCastHolder().getCastNodes();
+        return casts;
+    }
+
+    class Casts {
+        private static final ConcurrentHashMap<Class<?>, Casts> castsMap = new ConcurrentHashMap<>();
+        private static final Casts empty = new Casts();
+
+        protected final CastBuilder casts;
+
+        private Casts() {
+            casts = new CastBuilder();
+        }
+
+        public Casts(Class<? extends NodeWithArgumentCasts> cls) {
+            casts = new CastBuilder(cls.getAnnotation(RBuiltin.class));
+            castsMap.put(cls, this);
+        }
+
+        public static void noCasts(Class<? extends NodeWithArgumentCasts> cls) {
+            castsMap.put(cls, new Casts(cls));
+        }
+
+        public static Casts forClass(Class<?> cls) {
+            return castsMap.get(cls);
+        }
+
+        public CastNode[] getCastNodes() {
+            return casts.getCasts();
+        }
+
+        public PreinitialPhaseBuilder arg(String argumentName) {
+            return casts.arg(argumentName);
+        }
+
+        public PreinitialPhaseBuilder arg(int argumentIndex, String argumentName) {
+            return casts.arg(argumentIndex, argumentName);
+        }
+
+        public PreinitialPhaseBuilder arg(int argumentIndex) {
+            return casts.arg(argumentIndex);
+        }
+
+        private static boolean noCastsAllowed(Class<?> cls) {
+            boolean res = RExternalBuiltinNode.Arg0.class.isAssignableFrom(cls) || UnaryArithmeticBuiltinNode.class.isAssignableFrom(cls) ||
+                            (RBuiltinNode.class.isAssignableFrom(cls) && hasNoArguments(cls));
+            return res;
+        }
+
+        private static boolean hasNoArguments(Class<?> cls) {
+            RBuiltin a = cls.getAnnotation(RBuiltin.class);
+            return a != null && a.parameterNames().length == 0;
+        }
+
+        private static Class<?> getBuiltinClass(Class<?> cls) {
+            if (cls.getAnnotation(GeneratedBy.class) != null) {
+                return cls.getSuperclass();
+            } else {
+                return cls;
+            }
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java
index 4449df431ef06c6e7f42bec23d7d94648877b661..579352ce12d9b2c9b7eff4fa13c13335e7d81dfc 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java
@@ -32,7 +32,6 @@ import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.nodes.function.FormalArguments;
 import com.oracle.truffle.r.nodes.function.RCallNode;
-import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinKind;
@@ -47,20 +46,10 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
 
 @TypeSystemReference(RTypes.class)
-public abstract class RBuiltinNode extends RBaseNode {
+public abstract class RBuiltinNode extends RBaseNode implements NodeWithArgumentCasts {
 
     public abstract Object executeBuiltin(VirtualFrame frame, Object... args);
 
-    protected void createCasts(@SuppressWarnings("unused") CastBuilder casts) {
-        // nothing to do
-    }
-
-    public CastNode[] getCasts() {
-        CastBuilder builder = new CastBuilder(getRBuiltin());
-        createCasts(builder);
-        return builder.getCasts();
-    }
-
     /**
      * Return the default values of the builtin's formal arguments. This is only valid for builtins
      * of {@link RBuiltinKind kind} PRIMITIVE or SUBSTITUTE. Only simple scalar constants and
@@ -132,4 +121,5 @@ public abstract class RBuiltinNode extends RBaseNode {
     public String toString() {
         return (getRBuiltin() == null ? getClass().getSimpleName() : getRBuiltin().name());
     }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RExternalBuiltinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RExternalBuiltinNode.java
index 60c5f72e5830f273253b0b708b2c0b9b9961d67f..8f4ad0a026fe1d885d3399bd7bb9f9a425cab5de 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RExternalBuiltinNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RExternalBuiltinNode.java
@@ -48,7 +48,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 @TypeSystemReference(RTypes.class)
-public abstract class RExternalBuiltinNode extends RBaseNode {
+public abstract class RExternalBuiltinNode extends RBaseNode implements NodeWithArgumentCasts {
 
     public Object call(@SuppressWarnings("unused") VirtualFrame frame, RArgsValuesAndNames args) {
         return call(args);
@@ -56,16 +56,6 @@ public abstract class RExternalBuiltinNode extends RBaseNode {
 
     protected abstract Object call(RArgsValuesAndNames args);
 
-    protected void createCasts(@SuppressWarnings("unused") CastBuilder casts) {
-        // nothing to do
-    }
-
-    public CastNode[] getCasts() {
-        CastBuilder builder = new CastBuilder();
-        createCasts(builder);
-        return builder.getCasts();
-    }
-
     // TODO: these should be in the build nodes
     @Child private CastLogicalNode castLogical;
     @Child private CastIntegerNode castInt;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInternalCodeBuiltinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInternalCodeBuiltinNode.java
index 78914ee9313f30da5b6375abe5aac790555c4695..05e91851108907a73d5716dc0e76df049bb96fa4 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInternalCodeBuiltinNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInternalCodeBuiltinNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,6 +48,10 @@ public final class RInternalCodeBuiltinNode extends RExternalBuiltinNode {
     @Child private CallMatcherNode call = CallMatcherNode.create(true);
     @CompilationFinal private RFunction function;
 
+    static {
+        Casts.noCasts(RInternalCodeBuiltinNode.class);
+    }
+
     public RInternalCodeBuiltinNode(RContext context, String basePackage, Source code, String functionName) {
         this.context = context;
         this.basePackage = basePackage;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java
index 98cb9ac462f88d4369bcdd8fcef2f042ebc0a09b..6d99e4f2ed1c49459477b97f0919038459544fc6 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.builtin.casts;
 
+import java.util.Optional;
 import java.util.function.Supplier;
 
 import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode;
@@ -63,7 +64,6 @@ import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapIfStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.NotNAStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.PipelineStepVisitor;
-import com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardedValuesAnalyser;
 import com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardingAnalysisResult;
 import com.oracle.truffle.r.nodes.unary.BypassNode;
 import com.oracle.truffle.r.nodes.unary.BypassNodeGen.BypassDoubleNodeGen;
@@ -113,11 +113,12 @@ public final class PipelineToCastNode {
         // nop: static class
     }
 
-    public static CastNode convert(PipelineConfig config, PipelineStep<?, ?> firstStep) {
-        return convert(config, firstStep, PipelineConfig.getFilterFactory(), PipelineConfig.getMapperFactory());
+    public static CastNode convert(PipelineConfig config, PipelineStep<?, ?> firstStep, Optional<ForwardingAnalysisResult> fwdAnalysisResult) {
+        return convert(config, firstStep, PipelineConfig.getFilterFactory(), PipelineConfig.getMapperFactory(), fwdAnalysisResult);
     }
 
-    public static CastNode convert(PipelineConfig config, PipelineStep<?, ?> firstStep, ArgumentFilterFactory filterFactory, ArgumentMapperFactory mapperFactory) {
+    public static CastNode convert(PipelineConfig config, PipelineStep<?, ?> firstStep, ArgumentFilterFactory filterFactory, ArgumentMapperFactory mapperFactory,
+                    Optional<ForwardingAnalysisResult> fwdAnalysisResult) {
         if (firstStep == null) {
             return BypassNode.create(config, null, mapperFactory, null);
         }
@@ -133,11 +134,9 @@ public final class PipelineToCastNode {
             return originalPipelineFactory.get();
         }
 
-        // TODO: the result of this analysis should be cached
-        ForwardedValuesAnalyser fwdAnalyser = new ForwardedValuesAnalyser();
-        ForwardingAnalysisResult fwdAnalytics = fwdAnalyser.analyse(firstStep);
-        if (fwdAnalytics.isAnythingForwarded()) {
-            return ValueForwardingNodeGen.create(fwdAnalytics, originalPipelineFactory);
+        ForwardingAnalysisResult fwdRes = fwdAnalysisResult.get();
+        if (fwdRes != null && fwdRes.isAnythingForwarded()) {
+            return ValueForwardingNodeGen.create(fwdRes, originalPipelineFactory);
         } else {
             return originalPipelineFactory.get();
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineBuilder.java
index 2efd6be46960733f0291507003945392721a8abe..b660585cb25644ca80ecff4b560c01519147bdcd 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineBuilder.java
@@ -22,6 +22,10 @@
  */
 package com.oracle.truffle.r.nodes.builtin.casts.fluent;
 
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
+
+import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.casts.Filter;
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper;
 import com.oracle.truffle.r.nodes.builtin.casts.MessageData;
@@ -35,6 +39,8 @@ import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.FindFirstStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapIfStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.NotNAStep;
+import com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardedValuesAnalyser;
+import com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardingAnalysisResult;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineToCastNode;
 import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -50,13 +56,14 @@ public final class PipelineBuilder {
 
     private final PipelineConfigBuilder pcb;
     private ChainBuilder<?> chainBuilder;
+    private final AtomicReference<Optional<ForwardingAnalysisResult>> fwdAnalysisResult = new AtomicReference<>();
 
     public PipelineBuilder(String argumentName) {
         this.pcb = new PipelineConfigBuilder(argumentName);
     }
 
     public CastNode buildNode() {
-        return PipelineToCastNode.convert(pcb.build(), getFirstStep());
+        return PipelineToCastNode.convert(pcb.build(), getFirstStep(), getFwdAnalysisResult());
     }
 
     public PreinitialPhaseBuilder fluent() {
@@ -147,4 +154,24 @@ public final class PipelineBuilder {
             chainBuilder.addStep(step);
         }
     }
+
+    public Optional<ForwardingAnalysisResult> getFwdAnalysisResult() {
+        Optional<ForwardingAnalysisResult> res = fwdAnalysisResult.get();
+        if (res == null) {
+            ForwardedValuesAnalyser fwdAnalyser = new ForwardedValuesAnalyser();
+            PipelineStep<?, ?> firstStep = getFirstStep();
+            if (firstStep == null) {
+                res = Optional.empty();
+            } else {
+                res = Optional.of(fwdAnalyser.analyse(firstStep));
+            }
+            if (fwdAnalysisResult.compareAndSet(null, res)) {
+                return res;
+            } else {
+                return fwdAnalysisResult.get();
+            }
+        } else {
+            return res;
+        }
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
index 2323cce098dbfe44d2b8e80562afc9d7dc2f706c..427b9c1c60c09e0bf19005119dbe5d29ada820d7 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
@@ -803,7 +803,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
                             arg = casts[i].execute(arg);
                         }
                     } else {
-                        assert casts.length <= i || casts[i] == null : "no casts allowed on non-evaluated arguments";
+                        assert casts.length <= i || casts[i] == null : "no casts allowed on non-evaluated arguments in builtin " + builtinDescriptor.getName();
                         if (arg instanceof RPromise || arg instanceof RMissing) {
                             if (!nonWrapSeen[i]) {
                                 CompilerDirectives.transferToInterpreterAndInvalidate();
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetPrimName.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetPrimName.java
index 1211e077b4e6e18d1e041b870baae76e1ce2907a..25920e40449e25802068ac9f1583534586c7af60 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetPrimName.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetPrimName.java
@@ -14,7 +14,6 @@ package com.oracle.truffle.r.nodes.objects;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.builtin;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -22,8 +21,8 @@ import com.oracle.truffle.r.runtime.data.RFunction;
 // transcribed from src/library/methods/src/utils.c
 public abstract class GetPrimName extends RExternalBuiltinNode.Arg1 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(GetPrimName.class);
         casts.arg(0).defaultError(RError.NO_CALLER, RError.Message.GENERIC, "'R_get_primname' called on a non-primitive").mustBe(builtin());
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java
index 59f2ef25c1c7f52e84f4af3196433f054aa74507..44d51c9a1b090d243560b7404add7150eccc27f1 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java
@@ -20,7 +20,6 @@ import com.oracle.truffle.r.nodes.access.AccessSlotNode;
 import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.nodes.unary.DuplicateNode;
@@ -47,8 +46,8 @@ public abstract class NewObject extends RExternalBuiltinNode.Arg1 {
         castLogicalScalar = newCastBuilder().asLogicalVector().findFirst(RRuntime.LOGICAL_NA).buildCastNode();
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(NewObject.class);
         // TODO: should we change the message to (incompatible) "Java level ..."?
         casts.arg(0).mustNotBeNull(RError.NO_CALLER, RError.Message.GENERIC, "C level NEW macro called with null class definition pointer");
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java
index a1e52ad1f1ecc8bc4851017311d51e9009f3b226..88d39a7818618db7cf039dd9f83d23c5fab0ee62 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java
@@ -31,6 +31,7 @@ import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -55,6 +56,10 @@ public abstract class UnaryNotNode extends RBuiltinNode {
     private final NAProfile naProfile = NAProfile.create();
     private final ConditionProfile zeroLengthProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(UnaryNotNode.class);
+    }
+
     private static byte not(byte value) {
         return (value == RRuntime.LOGICAL_TRUE ? RRuntime.LOGICAL_FALSE : RRuntime.LOGICAL_TRUE);
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RBaseNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RBaseNode.java
index d4f9f6d33c68d82e1d813a62862225fe89da029e..730c1b5a772da628f5e7e2e44c66b5191f2aad91 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RBaseNode.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RBaseNode.java
@@ -140,6 +140,17 @@ public abstract class RBaseNode extends Node {
         Node current = this;
         while (current != null) {
             if (current instanceof RSyntaxNode && ((RSyntaxNode) current).isSyntax()) {
+                if (current instanceof RSyntaxCall) {
+                    RSyntaxCall call = (RSyntaxCall) current;
+                    if (call.getSyntaxArguments().length > 0 && call.getSyntaxLHS() instanceof RSyntaxLookup &&
+                                    ((RSyntaxLookup) call.getSyntaxLHS()).getIdentifier().equals(".Internal")) {
+                        // unwrap .Internal calls
+                        RSyntaxElement firstArg = call.getSyntaxArguments()[0];
+                        if (firstArg instanceof RSyntaxNode) {
+                            return (RSyntaxNode) firstArg;
+                        }
+                    }
+                }
                 return (RSyntaxNode) current;
             }
             current = current.getParent();
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asfunction.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asfunction.java
index 95b6ce40cdbe5442990d31fa483f141e632c6951..063819596e5ef87e2dabae41d85b56728fbaa3a5 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asfunction.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asfunction.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,7 @@ public class TestBuiltin_asfunction extends TestBase {
         assertEval("{ as.function(alist(\"foo\"))() }");
         assertEval("{ as.function(alist(7+42i))() }");
         assertEval("{ as.function(alist(as.raw(7)))() }");
-        assertEval(Output.IgnoreErrorContext, "{ .Internal(as.function.default(alist(a+b), \"foo\")) }");
+        assertEval("{ .Internal(as.function.default(alist(a+b), \"foo\")) }");
         assertEval(Output.IgnoreErrorContext, "{ .Internal(as.function.default(function() 42, parent.frame())) }");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asvector.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asvector.java
index 6ebebb950d5909849c7a6b02cf45733ff75c3941..671161d6d806b1213fdbc8037f30ee9fb5a8aa09 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asvector.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asvector.java
@@ -422,9 +422,9 @@ public class TestBuiltin_asvector extends TestBase {
         assertEval("as.vector(x~z)");
         assertEval("as.vector(file(''))");
 
-        assertEval(Output.IgnoreErrorContext, "{ as.vector(42, NULL) }");
-        assertEval(Output.IgnoreErrorContext, "{ as.vector(42, c(\"character\", \"character\")) }");
-        assertEval(Output.IgnoreErrorContext, "{ as.vector(42, character())  }");
+        assertEval("{ as.vector(42, NULL) }");
+        assertEval("{ as.vector(42, c(\"character\", \"character\")) }");
+        assertEval("{ as.vector(42, character())  }");
     }
 
     @Test