diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
index 438bccd17c05f57b5621b8b478ef68ff75fe6749..2d7a58097af76ff35e25cb011c195906091de8d8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
@@ -503,6 +503,7 @@ public class BasePackage extends RBuiltinPackage {
         add(Formals.class, FormalsNodeGen::create);
         add(Format.class, FormatNodeGen::create);
         add(FormatC.class, FormatCNodeGen::create);
+        add(FormatInfo.class, FormatInfoNodeGen::create);
         add(FortranAndCFunctions.DotC.class, FortranAndCFunctionsFactory.DotCNodeGen::create);
         add(FortranAndCFunctions.Fortran.class, FortranAndCFunctionsFactory.FortranNodeGen::create);
         add(FrameFunctions.MatchCall.class, FrameFunctionsFactory.MatchCallNodeGen::create);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatInfo.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..2599ec78c37b570c9e890707f656aa783c68582d
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatInfo.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2017, 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.base;
+
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.constant;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lte;
+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.Cached;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.base.printer.ComplexVectorMetrics;
+import com.oracle.truffle.r.nodes.builtin.base.printer.ComplexVectorPrinter;
+import com.oracle.truffle.r.nodes.builtin.base.printer.DoubleVectorMetrics;
+import com.oracle.truffle.r.nodes.builtin.base.printer.DoubleVectorPrinter;
+import com.oracle.truffle.r.nodes.builtin.base.printer.PrintParameters;
+import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.builtins.RBuiltin;
+import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
+import com.oracle.truffle.r.runtime.ops.na.NACheck;
+
+/**
+ * Information is returned on how format() would be formatted.
+ */
+@RBuiltin(name = "format.info", kind = INTERNAL, parameterNames = {"x", "digits", "nsmall"}, behavior = PURE)
+public abstract class FormatInfo extends RBuiltinNode.Arg3 {
+
+    static {
+        Casts casts = new Casts(FormatInfo.class);
+        casts.arg(0).mustBe(abstractVectorValue(), Message.ATOMIC_VECTOR_ARGUMENTS_ONLY);
+        casts.arg(1).mapNull(constant(-1)).mustNotBeNA(Message.INVALID_ARGUMENT, "digits").asIntegerVector().findFirst().mustBe(gte(0).or(lte(22)));
+        casts.arg(2).mustNotBeNA(Message.INVALID_ARGUMENT, "nsmall").asIntegerVector().findFirst().mustBe(gte(0).or(lte(20)));
+    }
+
+    @Specialization
+    protected int doInt(int n, @SuppressWarnings("unused") int digits, @SuppressWarnings("unused") int nsmall,
+                    @Cached("create()") VectorFactory factory) {
+        return (n == RRuntime.INT_NA) ? 2 : intLength(n);
+    }
+
+    @Specialization
+    protected int doString(String s, int digits, int nsmall) {
+        return s.length();
+    }
+
+    @Specialization(guards = "vAccess.supports(v)")
+    protected Object doVector(RAbstractVector v, int digits, int nsmall,
+                    @Cached("v.access()") VectorAccess vAccess,
+                    @Cached("create()") VectorFactory factory) {
+
+        switch (vAccess.getType()) {
+            case Integer: {
+                SequentialIterator vIter = vAccess.access(v);
+                boolean naFound = false;
+                if (!vAccess.next(vIter)) {
+                    return 1;
+                }
+                int vMin = vAccess.getInt(vIter);
+                if (vAccess.na.check(vMin)) {
+                    vMin = 0; // Anything <= "NA".length()
+                    naFound = true;
+                }
+                int vMax = vMin;
+                while (vAccess.next(vIter)) {
+                    int n = vAccess.getInt(vIter);
+                    if (!vAccess.na.check(n)) {
+                        vMin = Math.min(vMin, n);
+                        vMax = Math.max(vMax, n);
+                    } else {
+                        naFound = true;
+                    }
+                }
+                int result;
+                if (vMin > 0) {
+                    result = nonNegativeIntLength(vMax);
+                } else if (vMax < 0) {
+                    result = intLength(vMin);
+                } else {
+                    result = intLength(vMax);
+                    if (vMin != vMax) {
+                        result = Math.max(result, intLength(vMin));
+                    }
+                }
+                if (naFound) {
+                    result = Math.max(result, 2);
+                }
+                return result;
+            }
+
+            case Double: {
+                PrintParameters pp = new PrintParameters();
+                pp.setDefaults();
+                if (digits != -1) {
+                    pp.setDigits(digits);
+                }
+                RandomIterator vIter = vAccess.randomAccess(v);
+                DoubleVectorMetrics dvm = DoubleVectorPrinter.formatDoubleVector(vIter, vAccess, 0, vAccess.getLength(vIter), nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth());
+                return factory.createIntVector(new int[]{dvm.getAdjustedMaxWidth(), dvm.d, dvm.e}, true);
+            }
+
+            case Complex: {
+                PrintParameters pp = new PrintParameters();
+                pp.setDefaults();
+                if (digits != -1) {
+                    pp.setDigits(digits);
+                }
+                RandomIterator vIter = vAccess.randomAccess(v);
+                ComplexVectorMetrics cvm = ComplexVectorPrinter.formatComplexVector(vIter, vAccess, 0, vAccess.getLength(vIter), nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth());
+                return factory.createIntVector(new int[]{cvm.wr, cvm.dr, cvm.er, cvm.wi, cvm.di, cvm.ei}, true);
+            }
+
+            case Logical: {
+                SequentialIterator vIter = vAccess.access(v);
+                int vMaxLen = 0;
+                while (vAccess.next(vIter)) {
+                    byte b = vAccess.getLogical(vIter);
+                    if (!vAccess.na.check(b)) {
+                        vMaxLen = Math.max(vMaxLen, (b == RRuntime.LOGICAL_TRUE) ? 4 : 5);
+                    } else {
+                        vMaxLen = Math.max(vMaxLen, 2);
+                    }
+                }
+                return vMaxLen;
+            }
+
+            case Raw: {
+                return 2;
+            }
+
+            case Character: {
+                SequentialIterator vIter = vAccess.access(v);
+                int vMaxLen = 0;
+                while (vAccess.next(vIter)) {
+                    String s = vAccess.getString(vIter);
+                    if (!vAccess.na.check(s)) {
+                        vMaxLen = Math.max(vMaxLen, s.length());
+                    }
+                }
+                return vMaxLen;
+            }
+
+            default:
+                throw new RInternalError("Unhandled type.");
+        }
+    }
+
+    @Specialization(replaces = "doVector")
+    protected Object doVectorGeneric(RAbstractVector v, int digits, int nsmall,
+                    @Cached("create()") VectorFactory factory) {
+        return doVector(v, digits, nsmall, v.slowPathAccess(), factory);
+    }
+
+    private static int intLength(int n) {
+        return (n < 0) ? (1 + nonNegativeIntLength(n)) : nonNegativeIntLength(n);
+    }
+
+    private static int nonNegativeIntLength(int n) {
+        // Avoid series of div operations which may be costly on some platforms
+        return (n < 10000)
+                        ? ((n < 100) ? ((n < 10) ? 1 : 2) : ((n < 1000) ? 3 : 4))
+                        : ((n < 1000000) ? ((n < 100000) ? 5 : 6) : ((n < 100000000) ? ((n < 10000000) ? 7 : 8) : ((n < 1000000000) ? 9 : 10)));
+        // int result = 1;
+        // while (n > 9) {
+        // result++;
+        // n /= 10;
+        // }
+        // return result;
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java
index 99957bfd751f46e4ab8d04a00db0119cc4f86153..83de319ffb0e4e726282674f61e1615aae7efbd1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java
@@ -81,7 +81,7 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe
     }
 
     @TruffleBoundary
-    static ComplexVectorMetrics formatComplexVector(RandomIterator iter, VectorAccess access, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) {
+    public static ComplexVectorMetrics formatComplexVector(RandomIterator iter, VectorAccess access, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) {
 
         /* format.info() or x[1..l] for both Re & Im */
         int rt;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java
index feef3ede00780b3cdcac6956f8df15e366ce5051..2a45c170d951d7c3e3644f631caf08f919ac6da6 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java
@@ -347,7 +347,7 @@ public abstract class InternalNode extends OperatorNode {
                     "qweibull", "dnchisq", "pnchisq", "qnchisq", "dnt", "pnt", "qnt", "dwilcox", "pwilcox", "qwilcox", "besselI", "besselK", "dnbinom_mu", "pnbinom_mu", "qnbinom_mu", "dhyper",
                     "phyper", "qhyper", "dnbeta", "pnbeta", "qnbeta", "dnf", "pnf", "qnf", "dtukey", "ptukey", "qtukey", "rchisq", "rexp", "rgeom", "rpois", "rt", "rsignrank", "rbeta", "rbinom",
                     "rcauchy", "rf", "rgamma", "rlnorm", "rlogis", "rnbinom", "rnbinom_mu", "rnchisq", "rnorm", "runif", "rweibull", "rwilcox", "rhyper",
-                    "format.info", "grepRaw", "regexec", "adist", "aregexec", "chartr", "strtrim", "eapply", "machine", "save", "dump", "prmatrix", "gcinfo",
+                    "grepRaw", "regexec", "adist", "aregexec", "chartr", "strtrim", "eapply", "machine", "save", "dump", "prmatrix", "gcinfo",
                     "memory.profile", "sys.on.exit", "builtins", "bodyCode", "rapply", "inspect",
                     "mem.limits", "capabilitiesX11", "Cstack_info", "file.choose", "polyroot",
                     "setNumMathThreads", "setMaxNumMathThreads", "isatty", "isIncomplete", "pipe", "fifo", "unz", "truncate", "rawConnection",
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
index 1253fd0cf72ca97ed5573ce9832a9b6545c36525..cd88daf77da7313162916f15b3f901219a15f86b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
@@ -913,7 +913,8 @@ public final class RError extends RuntimeException implements TruffleException {
         UNEXPECTED_OBJ_IN_SIZE("Unexpected object type %s while calculating estimated object size."),
         BAD_CONSTANT_COUNT("bad constant count"),
         MUST_BE_MULTIPLE("argument '%s' must be a multiple of %d long"),
-        MUSTNOT_CONTAIN_NAS("argument '%s' must not contain NAs");
+        MUSTNOT_CONTAIN_NAS("argument '%s' must not contain NAs"),
+        ATOMIC_VECTOR_ARGUMENTS_ONLY("atomic vector arguments only");
 
         public final String message;
         final boolean hasArgs;
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index d1fe132529d3ad8f8f3dc5aa0036a2c8d7fcb8a2..b9b6a1580b013c752d1608f805fd8fa93e3b6a52 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -26995,59 +26995,108 @@ character(0)
 #argv <- structure(list(x = structure(c(0, 30, 60), units = 'mins',     class = 'difftime')), .Names = 'x');do.call('format.difftime', argv)
 [1] " 0 mins" "30 mins" "60 mins"
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo1#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo1#
 #argv <- list(c(0.099999994, 0.2), 7L, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))
 [1] 10  8  0
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo10#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo10#
 #argv <- list(structure(c(2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3, 0, 6, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), .Names = c('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y')), NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))
 [1] 1 0 0
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo11#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo11#
 #argv <- list(structure(c(-3.14159265358979e-05, 3.14159265358979e-05, -0.000314159265358979, 0.000314159265358979, -0.00314159265358979, 0.00314159265358979, -0.0314159265358979, 0.0314159265358979, -0.314159265358979, 0.314159265358979, -3.14159265358979, 3.14159265358979, -31.4159265358979, 31.4159265358979, -314.159265358979, 314.159265358979, -3141.59265358979, 3141.59265358979, -31415.9265358979, 31415.9265358979, -314159.265358979, 314159.265358979, -1e-05, 1e-05, -1e-04, 1e-04, -0.001, 0.001, -0.01, 0.01, -0.1, 0.1), .Dim = c(2L, 16L)), NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))
 [1] 13  6  1
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo12#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo12#
 #argv <- list(c(NaN, NA), NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))
 [1] 3 0 0
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo14#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo14#
 #argv <- structure(list(x = complex(real = Inf, imaginary = Inf)),     .Names = 'x');do.call('format.info', argv)
 [1] 3 0 0 3 0 0
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo15#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo15#
 #argv <- structure(list(x = c(complex(real = NaN, imaginary = NaN),     NA)), .Names = 'x');do.call('format.info', argv)
 [1] 3 0 0 3 0 0
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo2#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo16#
+#.Internal(format.info(1+2i, NULL, 1))
+[1] 3 1 0 3 1 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo16#
+#.Internal(format.info(1, 2, NA))
+Error: invalid 'nsmall' argument
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo16#
+#.Internal(format.info(1, 2, NULL))
+Error: invalid 'nsmall' argument
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo16#
+#.Internal(format.info(1, NA, 1))
+Error: invalid 'digits' argument
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo16#
+#.Internal(format.info(1, NULL, 1))
+[1] 3 1 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo16#
+#.Internal(format.info(NA, 1, 1))
+[1] 2
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo16#
+#.Internal(format.info(NULL, 1, 1))
+Error: atomic vector arguments only
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo16#
+#.Internal(format.info(c('a',NA) , NULL, 1))
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo16#
+#.Internal(format.info(c(1,NA,3) , NULL, NULL))
+Error: invalid 'nsmall' argument
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo16#
+#.Internal(format.info(c(1L,NA,3L) , NULL, 1)); .Internal(format.info(c(1L, 3L) , NULL, 1))
+[1] 2
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo16#
+#.Internal(format.info(environment(), NULL, 1))
+Error: atomic vector arguments only
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo16#
+#.Internal(format.info(paste, NULL, 1))
+Error: atomic vector arguments only
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo2#
 #argv <- list(c(0.099999994, 0.2), 6L, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))
 [1] 3 1 0
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo3#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo3#
 #argv <- list(c(Inf, -Inf), NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))
 [1] 4 0 0
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo4#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo4#
 #argv <- list(FALSE, NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))
 [1] 5
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo5#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo5#
 #argv <- list(3.14159265358979e-10, NULL, 8); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))
 [1] 12  6  1
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo6#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo6#
 #argv <- list(1e+08, NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))
 [1] 5 0 1
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo7#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo7#
 #argv <- list(1e+222, NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))
 [1] 6 0 2
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo8#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo8#
 #argv <- list(31.4159265358979, NULL, 8); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))
 [1] 11  8  0
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo9#Ignored.Unimplemented#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_formatinfo.testformatinfo9#
 #argv <- list(712L, NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))
 [1] 3
 
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_formatinfo.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_formatinfo.java
index 771f3239267c833de99faed7211fac72332a881b..e250ae3e2f33cb58966686de0617addf3f17a964 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_formatinfo.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_formatinfo.java
@@ -19,87 +19,88 @@ public class TestBuiltin_formatinfo extends TestBase {
 
     @Test
     public void testformatinfo1() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented, "argv <- list(c(0.099999994, 0.2), 7L, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(c(0.099999994, 0.2), 7L, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
     public void testformatinfo2() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented, "argv <- list(c(0.099999994, 0.2), 6L, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(c(0.099999994, 0.2), 6L, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
     public void testformatinfo3() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented, "argv <- list(c(Inf, -Inf), NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(c(Inf, -Inf), NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
     public void testformatinfo4() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented, "argv <- list(FALSE, NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(FALSE, NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
     public void testformatinfo5() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented, "argv <- list(3.14159265358979e-10, NULL, 8); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(3.14159265358979e-10, NULL, 8); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
     public void testformatinfo6() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented, "argv <- list(1e+08, NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(1e+08, NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
     public void testformatinfo7() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented, "argv <- list(1e+222, NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(1e+222, NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
     public void testformatinfo8() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented, "argv <- list(31.4159265358979, NULL, 8); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(31.4159265358979, NULL, 8); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
     public void testformatinfo9() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented, "argv <- list(712L, NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(712L, NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
     public void testformatinfo10() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented,
-                        "argv <- list(structure(c(2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3, 0, 6, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), .Names = c('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y')), NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(structure(c(2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3, 0, 6, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), .Names = c('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y')), NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
     public void testformatinfo11() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented,
-                        "argv <- list(structure(c(-3.14159265358979e-05, 3.14159265358979e-05, -0.000314159265358979, 0.000314159265358979, -0.00314159265358979, 0.00314159265358979, -0.0314159265358979, 0.0314159265358979, -0.314159265358979, 0.314159265358979, -3.14159265358979, 3.14159265358979, -31.4159265358979, 31.4159265358979, -314.159265358979, 314.159265358979, -3141.59265358979, 3141.59265358979, -31415.9265358979, 31415.9265358979, -314159.265358979, 314159.265358979, -1e-05, 1e-05, -1e-04, 1e-04, -0.001, 0.001, -0.01, 0.01, -0.1, 0.1), .Dim = c(2L, 16L)), NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(structure(c(-3.14159265358979e-05, 3.14159265358979e-05, -0.000314159265358979, 0.000314159265358979, -0.00314159265358979, 0.00314159265358979, -0.0314159265358979, 0.0314159265358979, -0.314159265358979, 0.314159265358979, -3.14159265358979, 3.14159265358979, -31.4159265358979, 31.4159265358979, -314.159265358979, 314.159265358979, -3141.59265358979, 3141.59265358979, -31415.9265358979, 31415.9265358979, -314159.265358979, 314159.265358979, -1e-05, 1e-05, -1e-04, 1e-04, -0.001, 0.001, -0.01, 0.01, -0.1, 0.1), .Dim = c(2L, 16L)), NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
     public void testformatinfo12() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented, "argv <- list(c(NaN, NA), NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(c(NaN, NA), NULL, 0L); .Internal(format.info(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
     public void testformatinfo14() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented, "argv <- structure(list(x = complex(real = Inf, imaginary = Inf)),     .Names = 'x');do.call('format.info', argv)");
+        assertEval("argv <- structure(list(x = complex(real = Inf, imaginary = Inf)),     .Names = 'x');do.call('format.info', argv)");
     }
 
     @Test
     public void testformatinfo15() {
-        // FIXME RInternalError: not implemented: .Internal format.info
-        assertEval(Ignored.Unimplemented, "argv <- structure(list(x = c(complex(real = NaN, imaginary = NaN),     NA)), .Names = 'x');do.call('format.info', argv)");
+        assertEval("argv <- structure(list(x = c(complex(real = NaN, imaginary = NaN),     NA)), .Names = 'x');do.call('format.info', argv)");
     }
+
+    @Test
+    public void testformatinfo16() {
+        assertEval(".Internal(format.info(NA, 1, 1))");
+        assertEval(".Internal(format.info(1, NA, 1))");
+        assertEval(".Internal(format.info(1, 2, NA))");
+        assertEval(".Internal(format.info(NULL, 1, 1))");
+        assertEval(".Internal(format.info(1, NULL, 1))");
+        assertEval(".Internal(format.info(1, 2, NULL))");
+        assertEval(".Internal(format.info(1+2i, NULL, 1))");
+        assertEval(".Internal(format.info(paste, NULL, 1))");
+        assertEval(".Internal(format.info(environment(), NULL, 1))");
+        assertEval(".Internal(format.info(c(1L,NA,3L) , NULL, 1)); .Internal(format.info(c(1L, 3L) , NULL, 1))");
+        assertEval(".Internal(format.info(c(1,NA,3) , NULL, NULL))");
+        assertEval(".Internal(format.info(c('a',NA) , NULL, 1))");
+    }
+
 }