From 01bfe05f661461f8c8ca04d1898fc31893f97c37 Mon Sep 17 00:00:00 2001
From: Adam Welc <adam.welc@oracle.com>
Date: Mon, 10 Nov 2014 17:19:06 +0100
Subject: [PATCH] Further enhancements to factor and data frame support.

---
 .../r/nodes/builtin/base/AnyDuplicated.java   | 20 ++--
 .../r/nodes/builtin/base/AsDouble.java        |  6 ++
 .../r/nodes/builtin/base/AsInteger.java       |  3 +-
 .../r/nodes/builtin/base/AsLogical.java       |  4 +-
 .../truffle/r/nodes/builtin/base/Format.java  | 14 ++-
 .../truffle/r/nodes/builtin/base/IsNA.java    |  6 ++
 .../r/nodes/builtin/base/IsTypeFunctions.java |  6 ++
 .../nodes/builtin/base/PrettyPrinterNode.java | 36 +++++++-
 .../r/nodes/builtin/base/Structure.java       |  7 +-
 .../r/nodes/builtin/base/TypeConvert.java     |  3 +-
 .../nodes/builtin/base/UpdateAttributes.java  | 15 +--
 .../nodes/builtin/base/UpdateStorageMode.java |  2 +-
 .../access/array/read/AccessArrayNode.java    |  3 +-
 .../array/write/UpdateArrayHelperNode.java    |  2 +-
 .../r/nodes/binary/BinaryBooleanNode.java     | 92 +++++++++----------
 .../truffle/r/nodes/binary/CastTypeNode.java  | 16 ++++
 .../r/nodes/unary/CastLogicalNode.java        | 14 +++
 .../oracle/truffle/r/runtime/RRuntime.java    |  2 +
 .../oracle/truffle/r/runtime/RSerialize.java  |  2 +-
 .../truffle/r/runtime/data/RAttributable.java |  7 +-
 .../truffle/r/runtime/data/RDataFactory.java  |  4 +-
 .../truffle/r/runtime/data/RFactor.java       | 11 ++-
 .../truffle/r/runtime/data/RVector.java       | 19 +++-
 .../RFactorToStringVectorClosure.java         | 15 ++-
 .../truffle/r/test/ExpectedTestOutput.test    | 53 +++++++++++
 .../oracle/truffle/r/test/all/AllTests.java   | 60 ++++++++++++
 .../r/test/simple/TestSimpleBuiltins.java     | 12 +++
 .../r/test/simple/TestSimpleDataFrames.java   |  5 +
 28 files changed, 342 insertions(+), 97 deletions(-)

diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java
index 6a090aa209..9f26ab728d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java
@@ -69,24 +69,24 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     }
 
     @Specialization(guards = {"!empty"})
-    protected int anyDuplicatedFromStart(VirtualFrame frame, RAbstractVector x, RAbstractVector incomparables, byte fromLast) {
+    protected int anyDuplicatedFromStart(VirtualFrame frame, RAbstractContainer x, RAbstractContainer incomparables, byte fromLast) {
         initChildren();
         RType xType = typeof.execute(frame, x);
         if (fromLastProfile.profile(fromLast == RRuntime.LOGICAL_TRUE)) {
-            return getIndexFromLast(x, (RAbstractVector) (castTypeNode.execute(frame, incomparables, xType)));
+            return getIndexFromLast(x, (RAbstractContainer) (castTypeNode.execute(frame, incomparables, xType)));
         } else {
-            return getIndexFromStart(x, (RAbstractVector) (castTypeNode.execute(frame, incomparables, xType)));
+            return getIndexFromStart(x, (RAbstractContainer) (castTypeNode.execute(frame, incomparables, xType)));
         }
     }
 
     @SuppressWarnings("unused")
     @Specialization(guards = "empty")
-    protected int anyDuplicatedEmpty(RAbstractVector x, RAbstractVector incomparables, byte fromLast) {
+    protected int anyDuplicatedEmpty(RAbstractContainer x, RAbstractContainer incomparables, byte fromLast) {
         return 0;
     }
 
     @TruffleBoundary
-    private static int getIndexFromStart(RAbstractVector x, RAbstractVector incomparables) {
+    private static int getIndexFromStart(RAbstractContainer x, RAbstractContainer incomparables) {
         HashSet<Object> incompContents = new HashSet<>();
         HashSet<Object> vectorContents = new HashSet<>();
         for (int i = 0; i < incomparables.getLength(); i++) {
@@ -106,7 +106,7 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     }
 
     @TruffleBoundary
-    private static int getIndexFromStart(RAbstractVector x) {
+    private static int getIndexFromStart(RAbstractContainer x) {
         HashSet<Object> vectorContents = new HashSet<>();
         vectorContents.add(x.getDataAtAsObject(0));
         for (int i = 1; i < x.getLength(); i++) {
@@ -120,7 +120,7 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     }
 
     @TruffleBoundary
-    public static int getIndexFromLast(RAbstractVector x, RAbstractVector incomparables) {
+    public static int getIndexFromLast(RAbstractContainer x, RAbstractContainer incomparables) {
         HashSet<Object> incompContents = new HashSet<>();
         HashSet<Object> vectorContents = new HashSet<>();
         for (int i = 0; i < incomparables.getLength(); i++) {
@@ -140,7 +140,7 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     }
 
     @TruffleBoundary
-    private static int getIndexFromLast(RAbstractVector x) {
+    private static int getIndexFromLast(RAbstractContainer x) {
         HashSet<Object> vectorContents = new HashSet<>();
         vectorContents.add(x.getDataAtAsObject(x.getLength() - 1));
         for (int i = x.getLength() - 2; i >= 0; i--) {
@@ -154,11 +154,11 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     }
 
     @SuppressWarnings("unused")
-    protected boolean isIncomparable(RAbstractVector x, byte incomparables, byte fromLast) {
+    protected boolean isIncomparable(RAbstractContainer x, byte incomparables, byte fromLast) {
         return incomparables == RRuntime.LOGICAL_TRUE;
     }
 
-    protected boolean empty(RAbstractVector x) {
+    protected boolean empty(RAbstractContainer x) {
         return x.getLength() == 0;
     }
 
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 096951c0d0..d60ee33042 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
@@ -137,4 +137,10 @@ public abstract class AsDouble extends RBuiltinNode {
         controlVisibility();
         return castDoubleVector(frame, vector);
     }
+
+    @Specialization
+    protected RDoubleVector asDouble(VirtualFrame frame, RFactor vector) {
+        return asDouble(frame, vector.getVector());
+    }
+
 }
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 ff874767f2..547ba5daa6 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
@@ -133,8 +133,7 @@ public abstract class AsInteger extends RBuiltinNode {
 
     @Specialization
     protected RIntVector asInteger(RFactor factor) {
-        controlVisibility();
-        return factor.getVector();
+        return asInteger(factor.getVector());
     }
 
 }
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 2a18bb988b..b50cb5243b 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
@@ -101,8 +101,8 @@ public abstract class AsLogical extends RBuiltinNode {
     }
 
     @Specialization
-    protected RLogicalVector asLogical(VirtualFrame frame, RAbstractVector vector) {
+    protected RLogicalVector asLogical(VirtualFrame frame, RAbstractContainer container) {
         controlVisibility();
-        return castLogicalVector(frame, vector);
+        return castLogicalVector(frame, container);
     }
 }
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 4e0c8e5e25..47f8b92b2b 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
@@ -167,7 +167,7 @@ public abstract class Format extends RBuiltinNode {
 
     @SuppressWarnings("unused")
     @Specialization(guards = "!wrongArgs")
-    protected RStringVector format(VirtualFrame frame, RAbstractIntVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec,
+    protected RStringVector format(RAbstractIntVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec,
                     RLogicalVector naEncodeVec, RAbstractVector sciVec) {
         if (value.getLength() == 0) {
             return RDataFactory.createEmptyStringVector();
@@ -248,12 +248,18 @@ public abstract class Format extends RBuiltinNode {
 
     @SuppressWarnings("unused")
     @Specialization(guards = "!wrongArgs")
-    protected RStringVector format(VirtualFrame frame, RStringVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec,
-                    RLogicalVector naEncodeVec, RAbstractVector sciVec) {
+    protected RStringVector format(RStringVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec,
+                    RAbstractVector sciVec) {
         // TODO: implement full semantics
         return value;
     }
 
+    @Specialization(guards = "!wrongArgs")
+    protected RStringVector format(RFactor value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec,
+                    RAbstractVector sciVec) {
+        return format(value.getVector(), trimVec, digitsVec, nsmallVec, widthVec, justifyVec, naEncodeVec, sciVec);
+    }
+
     // TruffleDSL bug - should not need multiple guards here
     protected boolean wrongArgsObject(@SuppressWarnings("unused") Object value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec,
                     RLogicalVector naEncodeVec, RAbstractVector sciVec) {
@@ -288,7 +294,7 @@ public abstract class Format extends RBuiltinNode {
         return false;
     }
 
-    protected boolean wrongArgs(RAbstractVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec,
+    protected boolean wrongArgs(RAbstractContainer value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec,
                     RAbstractVector sciVec) {
         return wrongArgsObject(value, trimVec, digitsVec, nsmallVec, widthVec, justifyVec, naEncodeVec, sciVec);
     }
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 c330411359..da6df56c0b 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
@@ -146,4 +146,10 @@ public abstract class IsNA extends RBuiltinNode {
         controlVisibility();
         return RRuntime.LOGICAL_FALSE;
     }
+
+    @Specialization
+    protected RLogicalVector isNA(RFactor value) {
+        return isNA(value.getVector());
+    }
+
 }
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 89570da0f4..4af928c4d3 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
@@ -103,6 +103,12 @@ public class IsTypeFunctions {
             return arg.getElementClass() == Object.class;
         }
 
+        @Specialization
+        protected byte isAtomic(RFactor arg) {
+            controlVisibility();
+            return RRuntime.LOGICAL_TRUE;
+        }
+
     }
 
     @RBuiltin(name = "is.call", kind = PRIMITIVE, parameterNames = {"x"})
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java
index 96e572bfb2..cd3c4edb71 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java
@@ -28,6 +28,7 @@ import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.Node.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
@@ -41,8 +42,10 @@ import com.oracle.truffle.r.nodes.function.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
 import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute;
+import com.oracle.truffle.r.runtime.data.closures.*;
 import com.oracle.truffle.r.runtime.data.model.*;
 import com.oracle.truffle.r.runtime.env.*;
+import com.oracle.truffle.r.runtime.ops.na.*;
 
 @SuppressWarnings("unused")
 @NodeChildren({@NodeChild(value = "operand", type = RNode.class), @NodeChild(value = "listElementName", type = RNode.class), @NodeChild(value = "quote", type = RNode.class),
@@ -518,9 +521,13 @@ public abstract class PrettyPrinterNode extends RNode {
                 resultBuilder.append(vector.getLength() - maxPrint);
                 resultBuilder.append(" entries ]");
             }
-            RAttributes attributes = vector.getAttributes();
-            if (attributes != null) {
-                resultBuilder.append(printAttributes(vector, attributes));
+            if (!(vector instanceof RFactorToStringVectorClosure)) {
+                // it's a bit of a hack, but factors are meant to be printed using the S3 function
+                // anyway - the idea is to suppress attribute printing for factors nested in lists
+                RAttributes attributes = vector.getAttributes();
+                if (attributes != null) {
+                    resultBuilder.append(printAttributes(vector, attributes));
+                }
             }
             return builderToString(resultBuilder);
         }
@@ -1014,6 +1021,8 @@ public abstract class PrettyPrinterNode extends RNode {
 
         @Child private PrettyPrinterNode prettyPrinter;
 
+        private final NACheck naCheck = NACheck.create();
+
         private void initCast(Object listElementName) {
             if (prettyPrinter == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
@@ -1121,6 +1130,27 @@ public abstract class PrettyPrinterNode extends RNode {
             return prettyPrintSingleElement(operand, listElementName, quote, right);
         }
 
+        // TODO: this should be handled by an S3 function
+        @TruffleBoundary
+        @Specialization
+        protected String prettyPrintListElement(RFactor operand, Object listElementName, byte quote, byte right) {
+            StringBuilder sb = new StringBuilder(prettyPrintSingleElement(RClosures.createFactorToStringVector(operand, naCheck), listElementName, RRuntime.LOGICAL_FALSE, right));
+            sb.append("\nLevels:");
+            Object attr = operand.getVector().getAttr(RRuntime.LEVELS_ATTR_KEY);
+            if (attr != null) {
+                if (attr instanceof String) {
+                    sb.append(" ");
+                    sb.append(attr.toString());
+                } else {
+                    RAbstractStringVector vec = (RAbstractStringVector) attr;
+                    for (int i = 0; i < vec.getLength(); i++) {
+                        sb.append(" ");
+                        sb.append(vec.getDataAt(i));
+                    }
+                }
+            }
+            return sb.toString();
+        }
     }
 
     @NodeChildren({@NodeChild(value = "operand", type = RNode.class), @NodeChild(value = "isQuoted", type = RNode.class)})
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Structure.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Structure.java
index 5b4deb5475..4ffba92c5d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Structure.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Structure.java
@@ -75,16 +75,17 @@ public abstract class Structure extends RBuiltinNode {
         Object[] values = args.getValues();
         String[] argNames = getSuppliedArgsNames();
         validateArgNames(argNames);
+        RAbstractContainer res = obj;
         for (int i = 0; i < values.length; i++) {
             Object value = fixupValue(values[i]);
             String attrName = fixupAttrName(argNames[i + 1]);
             if (value == RNull.instance) {
-                obj.removeAttr(attrName);
+                res.removeAttr(attrName);
             } else {
-                obj.setAttr(attrName, value);
+                res = (RAbstractContainer) res.setAttr(attrName, value);
             }
         }
-        return obj;
+        return res;
     }
 
     private Object fixupValue(Object value) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TypeConvert.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TypeConvert.java
index 0c2b3c7a78..b00fa7944d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TypeConvert.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TypeConvert.java
@@ -164,8 +164,7 @@ public abstract class TypeConvert extends RBuiltinNode {
             }
             RIntVector res = RDataFactory.createIntVector(data, complete);
             res.setLevels(RDataFactory.createStringVector(levelsArray, RDataFactory.COMPLETE_VECTOR));
-            RVector.setClassAttr(res, RDataFactory.createStringVector("factor"), null, null);
-            return RDataFactory.createFactor(res);
+            return RVector.setClassAttr(res, RDataFactory.createStringVector("factor"), null, 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 e057dd8e85..196a22df5b 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
@@ -89,7 +89,7 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode {
     }
 
     @Specialization
-    protected RAbstractVector updateAttributes(VirtualFrame frame, RAbstractContainer container, RList list) {
+    protected RAbstractContainer updateAttributes(VirtualFrame frame, RAbstractContainer container, RList list) {
         controlVisibility();
         Object listNamesObject = list.getNames();
         if (listNamesObject == null || listNamesObject == RNull.instance) {
@@ -97,6 +97,7 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode {
         }
         RStringVector listNames = (RStringVector) listNamesObject;
         RVector resultVector = container.materializeNonSharedVector();
+        RAbstractContainer res = resultVector;
         if (numAttributesProfile.profile(list.getLength() == 0)) {
             resultVector.resetAllAttributes(true);
         } else {
@@ -113,9 +114,9 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode {
             // set the dim attribute first
             setDimAttribute(frame, resultVector, list);
             // set the remaining attributes in order
-            setRemainingAttributes(frame, container, resultVector, list);
+            res = setRemainingAttributes(frame, container, resultVector, list);
         }
-        return resultVector;
+        return res;
     }
 
     @TruffleBoundary
@@ -155,10 +156,11 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode {
     }
 
     @ExplodeLoop
-    private void setRemainingAttributes(VirtualFrame virtualFrame, RAbstractContainer container, RVector resultVector, RList sourceList) {
+    private RAbstractContainer setRemainingAttributes(VirtualFrame virtualFrame, RAbstractContainer container, RVector resultVector, RList sourceList) {
         RStringVector listNames = (RStringVector) sourceList.getNames();
         int length = sourceList.getLength();
         assert length > 0 : "Length should be > 0 for ExplodeLoop";
+        RAbstractContainer res = resultVector;
         for (int i = 0; i < sourceList.getLength(); i++) {
             Object value = sourceList.getDataAt(i);
             String attrName = listNames.getDataAt(i);
@@ -174,9 +176,9 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode {
                 }
             } else if (attrName.equals(RRuntime.CLASS_ATTR_KEY)) {
                 if (value == RNull.instance) {
-                    RVector.setClassAttr(resultVector, null, container.getElementClass() == RDataFrame.class ? container : null, container.getElementClass() == RFactor.class ? container : null);
+                    res = RVector.setClassAttr(resultVector, null, container.getElementClass() == RDataFrame.class ? container : null, container.getElementClass() == RFactor.class ? container : null);
                 } else {
-                    UpdateAttr.setClassAttrFromObject(resultVector, container, value, getEncapsulatingSourceSection());
+                    res = UpdateAttr.setClassAttrFromObject(resultVector, container, value, getEncapsulatingSourceSection());
                 }
             } else if (attrName.equals(RRuntime.ROWNAMES_ATTR_KEY)) {
                 resultVector.setRowNames(castVector(virtualFrame, value));
@@ -190,6 +192,7 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode {
                 }
             }
         }
+        return res;
     }
 
     @Fallback
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 200ede3e97..9203dd89db 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
@@ -64,7 +64,7 @@ public abstract class UpdateStorageMode extends RBuiltinNode {
                     if (attrs != null) {
                         RAttributable rresult = (RAttributable) result;
                         for (RAttribute attr : attrs) {
-                            rresult.setAttr(attr.getName(), attr.getValue());
+                            rresult = rresult.setAttr(attr.getName(), attr.getValue());
                         }
                     }
                 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/AccessArrayNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/AccessArrayNode.java
index 16c744e70c..623bd07b9d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/AccessArrayNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/AccessArrayNode.java
@@ -189,8 +189,7 @@ public abstract class AccessArrayNode extends RNode {
     protected Object accessFactor(VirtualFrame frame, RFactor factor, int recLevel, Object position, RAbstractLogicalVector dropDim) {
         RIntVector res = (RIntVector) castVector(frame, accessRecursive(frame, factor.getVector(), position, recLevel, dropDim));
         res.setLevels(factor.getVector().getAttr(RRuntime.LEVELS_ATTR_KEY));
-        RVector.setClassAttr(res, RDataFactory.createStringVector("factor"), null, null);
-        return RDataFactory.createFactor(res);
+        return RVector.setClassAttr(res, RDataFactory.createStringVector("factor"), null, null);
     }
 
     @SuppressWarnings("unused")
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/UpdateArrayHelperNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/UpdateArrayHelperNode.java
index 1b3c4aeb31..5892d9d534 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/UpdateArrayHelperNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/UpdateArrayHelperNode.java
@@ -203,7 +203,7 @@ public abstract class UpdateArrayHelperNode extends RNode {
         }
     }
 
-    @Specialization
+    @Specialization(guards = "isSubset")
     protected Object update(VirtualFrame frame, Object v, RFactor value, int recLevel, Object positions, Object vector) {
         return updateRecursive(frame, v, value.getVector(), vector, positions, recLevel);
     }
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 d8c732f9d6..d1a4c5b129 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
@@ -703,72 +703,72 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
 
     // factor and scalar
 
-    @Specialization(guards = "!isEq")
+    @Specialization(guards = "!meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, Object right) {
         throw RError.error(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
     }
 
-    @Specialization(guards = "!isEq")
+    @Specialization(guards = "!meaningfulOp")
     protected RLogicalVector doFactorOp(Object left, RFactor right) {
         throw RError.error(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, int right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.intToString(right, false), false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(int left, RFactor right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.intToString(left, false), true);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, double right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.doubleToString(right), false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(double left, RFactor right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.doubleToString(left), true);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, byte right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.logicalToString(right), false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(byte left, RFactor right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.logicalToString(left), false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, String right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), right, false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(String left, RFactor right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), left, true);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, RComplex right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.complexToString(right), false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RComplex left, RFactor right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.complexToString(left), true);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, RRaw right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.rawToString(right), false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RRaw left, RFactor right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.rawToString(left), true);
     }
@@ -863,22 +863,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
         return performStringVectorOpSameLength(left, RClosures.createIntToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doIntVectorDifferentLength(RAbstractIntVector left, RFactor right) {
         return performStringVectorOpDifferentLength(RClosures.createIntToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doIntVectorSameLength(RAbstractIntVector left, RFactor right) {
         return performStringVectorOpSameLength(RClosures.createIntToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doIntVectorDifferentLength(RFactor left, RAbstractIntVector right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createIntToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doIntVectorSameLength(RFactor left, RAbstractIntVector right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createIntToStringVector(right, rightNACheck));
     }
@@ -975,22 +975,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
         return performStringVectorOpSameLength(left, RClosures.createDoubleToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doDoubleVectorDifferentLength(RAbstractDoubleVector left, RFactor right) {
         return performStringVectorOpDifferentLength(RClosures.createDoubleToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doDoubleVectorSameLength(RAbstractDoubleVector left, RFactor right) {
         return performStringVectorOpSameLength(RClosures.createDoubleToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doDoubleVectorDifferentLength(RFactor left, RAbstractDoubleVector right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createDoubleToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doDoubleVectorSameLength(RFactor left, RAbstractDoubleVector right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createDoubleToStringVector(right, rightNACheck));
     }
@@ -1067,22 +1067,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
         return performStringVectorOpSameLength(left, RClosures.createLogicalToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doLogicalVectorDifferentLength(RAbstractLogicalVector left, RFactor right) {
         return performStringVectorOpDifferentLength(RClosures.createLogicalToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doLogicalVectorSameLength(RAbstractLogicalVector left, RFactor right) {
         return performStringVectorOpSameLength(RClosures.createLogicalToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doLogicalVectorDifferentLength(RFactor left, RAbstractLogicalVector right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createLogicalToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doLogicalVectorSameLength(RFactor left, RAbstractLogicalVector right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createLogicalToStringVector(right, rightNACheck));
     }
@@ -1139,22 +1139,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
         return performStringVectorOpSameLength(left, right);
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLength(RStringVector left, RFactor right) {
         return performStringVectorOpDifferentLength(left, RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLength(RStringVector left, RFactor right) {
         return performStringVectorOpSameLength(left, RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLength(RFactor left, RStringVector right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, rightNACheck), right);
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLength(RFactor left, RStringVector right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, rightNACheck), right);
     }
@@ -1201,52 +1201,52 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
 
     // factor and vectors
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLength(RFactor left, RFactor right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLength(RFactor left, RFactor right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLength(RFactor left, RAbstractComplexVector right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createComplexToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLength(RFactor left, RAbstractComplexVector right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createComplexToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLength(RAbstractComplexVector left, RFactor right) {
         return performStringVectorOpDifferentLength(RClosures.createComplexToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLength(RAbstractComplexVector left, RFactor right) {
         return performStringVectorOpSameLength(RClosures.createComplexToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLength(RFactor left, RRawVector right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createRawToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLength(RFactor left, RRawVector right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createRawToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLengthRRawVector(RRawVector left, RFactor right) {
         return performStringVectorOpDifferentLength(RClosures.createRawToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLengthRRawVector(RRawVector left, RFactor right) {
         return performStringVectorOpSameLength(RClosures.createRawToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, rightNACheck));
     }
@@ -1338,16 +1338,16 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
 
     // guards
 
-    public boolean isEq(RFactor left, RFactor right) {
-        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual;
+    public boolean meaningfulOp(RFactor left, RFactor right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || (left.isOrdered() && right.isOrdered());
     }
 
-    public boolean isEq(RFactor left, Object right) {
-        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual;
+    public boolean meaningfulOp(RFactor left, Object right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || left.isOrdered();
     }
 
-    public boolean isEq(Object left, RFactor right) {
-        return !(logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual);
+    public boolean meaningfulOp(Object left, RFactor right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || right.isOrdered();
     }
 
     private boolean isVectorizedLogicalOp() {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
index facf67fe88..20559f41ad 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
@@ -31,6 +31,8 @@ public abstract class CastTypeNode extends BinaryNode {
     @Child private CastToVectorNode castToVectorNode;
     @Child private TypeofNode typeof;
 
+    @Child private CastTypeNode castRecursive;
+
     public abstract Object execute(VirtualFrame frame, Object value, RType type);
 
     @SuppressWarnings("unused")
@@ -94,6 +96,12 @@ public abstract class CastTypeNode extends BinaryNode {
         return null;
     }
 
+    @Specialization
+    protected Object doCastDataFrame(VirtualFrame frame, RDataFrame value, RType type) {
+        initCastRecursive();
+        return castRecursive.execute(frame, value.getVector(), type);
+    }
+
     @SuppressWarnings("unused")
     protected static boolean isString(RAbstractVector value, RType type) {
         return type == RType.Character;
@@ -190,4 +198,12 @@ public abstract class CastTypeNode extends BinaryNode {
             castListNode = insert(CastListNodeFactory.create(null, false, false, false));
         }
     }
+
+    private void initCastRecursive() {
+        if (castRecursive == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            castRecursive = insert(CastTypeNodeFactory.create(null, null));
+        }
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
index 0a6857b8a7..10268ef185 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
+import java.util.*;
+
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.*;
@@ -179,6 +181,18 @@ public abstract class CastLogicalNode extends CastNode {
         return missing;
     }
 
+    @Specialization
+    protected Object asLogical(VirtualFrame frame, RDataFrame dataFrame) {
+        return castLogicalRecursive(frame, dataFrame.getVector());
+    }
+
+    @Specialization
+    protected RLogicalVector asLogical(RFactor factor) {
+        byte[] data = new byte[factor.getLength()];
+        Arrays.fill(data, RRuntime.LOGICAL_NA);
+        return RDataFactory.createLogicalVector(data, RDataFactory.INCOMPLETE_VECTOR);
+    }
+
     @Fallback
     @TruffleBoundary
     public int doOther(Object operand) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
index 69f26f12cc..38bebb8777 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
@@ -100,6 +100,8 @@ public class RRuntime {
     public static final String[] CLASS_INTEGER = new String[]{"integer", "numeric"};
     public static final String[] CLASS_DOUBLE = new String[]{"double", "numeric"};
 
+    public static final String CLASS_ORDERED = "ordered";
+
     public static final String WHICH = "which";
 
     public static final String WHAT = "what";
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
index 290652e0f5..30a6913553 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
@@ -362,7 +362,7 @@ public class RSerialize {
                     } else if (tag.equals(RRuntime.ROWNAMES_ATTR_KEY)) {
                         vec.setRowNames(car);
                     } else if (tag.equals(RRuntime.CLASS_ATTR_KEY)) {
-                        RVector.setClassAttr(vec, (RStringVector) car, null, null);
+                        result = RVector.setClassAttr(vec, (RStringVector) car, null, null);
                     } else {
                         vec.setAttr(tag, car);
                     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java
index 2746fdb5ea..3c51b93d1b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java
@@ -46,19 +46,20 @@ public interface RAttributable {
 
     /**
      * Set the attribute {@code name} to {@code value}, overwriting any existing value. This is
-     * generic; a class may need to override this to handle certain attributes specially,
+     * generic; a class may need to override this to handle certain attributes specially.
      */
-    default void setAttr(String name, Object value) {
+    default RAttributable setAttr(String name, Object value) {
         RAttributes attributes = getAttributes();
         if (attributes == null) {
             attributes = initAttributes();
         }
         attributes.put(name, value);
+        return this;
     }
 
     /**
      * Remove the attribute {@code name}. No error if {@code name} is not an attribute. This is
-     * generic; a class may need to override this to handle certain attributes specially,
+     * generic; a class may need to override this to handle certain attributes specially.
      */
     default void removeAttr(String name) {
         RAttributes attributes = getAttributes();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
index d7ae5ec067..1d19b5ae62 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
@@ -304,8 +304,8 @@ public final class RDataFactory {
         return traceDataCreated(new RExpression(list));
     }
 
-    public static RFactor createFactor(RIntVector vector) {
-        return traceDataCreated(new RFactor(vector));
+    public static RFactor createFactor(RIntVector vector, boolean ordered) {
+        return traceDataCreated(new RFactor(vector, ordered));
     }
 
     public static RVector createObjectVector(Object[] data, boolean completeVector) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java
index 2d4d8aa74e..600a7da4ee 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java
@@ -28,14 +28,21 @@ public final class RFactor implements RShareable, RAbstractContainer {
 
     private RIntVector vector;
 
-    public RFactor(RIntVector vector) {
+    private final boolean ordered;
+
+    public RFactor(RIntVector vector, boolean ordered) {
         this.vector = vector;
+        this.ordered = ordered;
     }
 
     public RIntVector getVector() {
         return vector;
     }
 
+    public boolean isOrdered() {
+        return ordered;
+    }
+
     @Override
     public int getLength() {
         return vector.getLength();
@@ -63,7 +70,7 @@ public final class RFactor implements RShareable, RAbstractContainer {
 
     @Override
     public RFactor copy() {
-        return RDataFactory.createFactor((RIntVector) vector.copy());
+        return RDataFactory.createFactor((RIntVector) vector.copy(), ordered);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
index 3db2391caf..2b3a6961a4 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
@@ -163,10 +163,11 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
     }
 
     @TruffleBoundary
-    public final void setAttr(String name, Object value) {
+    public final RAbstractContainer setAttr(String name, Object value) {
         if (attributes == null) {
             initAttributes();
         }
+        RAbstractContainer res = this;
         if (name.equals(RRuntime.NAMES_ATTR_KEY)) {
             setNames(value);
         } else if (name.equals(RRuntime.DIM_ATTR_KEY)) {
@@ -180,10 +181,11 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
         } else if (name.equals(RRuntime.ROWNAMES_ATTR_KEY)) {
             setRowNames(value);
         } else if (name.equals(RRuntime.CLASS_ATTR_KEY)) {
-            setClassAttr(this, (RStringVector) value, null, null);
+            res = setClassAttr(this, (RStringVector) value, null, null);
         } else {
             attributes.put(name, value);
         }
+        return res;
     }
 
     public final Object getAttr(String name) {
@@ -405,8 +407,15 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
             // class attribute removed - no longer a data frame (even if it was before)
             return vector;
         } else if (classAttr != null && classAttr.getLength() != 0) {
+            boolean ordered = false;
             for (int i = 0; i < classAttr.getLength(); i++) {
-                if (RType.DataFrame.getName().equals(classAttr.getDataAt(i))) {
+                String attr = classAttr.getDataAt(i);
+                if (RRuntime.CLASS_ORDERED.equals(attr)) {
+                    // "ordered" must be specified before "factor" - hence it's enough to do the
+                    // check only before encountering the "factor"
+                    ordered = true;
+                }
+                if (RType.DataFrame.getName().equals(attr)) {
                     vector.putAttribute(RRuntime.CLASS_ATTR_KEY, classAttr);
                     if (enclosingDataFrame != null) {
                         // was a frame and still is a frame
@@ -415,7 +424,7 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
                         // it's a data frame now
                         return RDataFactory.createDataFrame(vector);
                     }
-                } else if (RType.Factor.getName().equals(classAttr.getDataAt(i))) {
+                } else if (RType.Factor.getName().equals(attr)) {
                     if (vector.getElementClass() != RInt.class) {
                         // TODO: add source section
                         throw RError.error(null, RError.Message.ADDING_INVALID_CLASS, "factor");
@@ -426,7 +435,7 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
                         return enclosingFactor;
                     } else {
                         // it's a factor now
-                        return RDataFactory.createFactor((RIntVector) vector);
+                        return RDataFactory.createFactor((RIntVector) vector, ordered);
                     }
                 }
             }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RFactorToStringVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RFactorToStringVectorClosure.java
index cb2c3ca812..e437f164d4 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RFactorToStringVectorClosure.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RFactorToStringVectorClosure.java
@@ -42,13 +42,24 @@ public class RFactorToStringVectorClosure extends RToStringVectorClosure impleme
         if (this.levels == null) {
             RError.warning(RError.Message.IS_NA_TO_NON_VECTOR, "NULL");
         }
+        naCheck.enable(this.vector);
     }
 
     public String getDataAt(int index) {
-        if (levels == null) {
+        if (levels == null || levels.getLength() == 0) {
             return RRuntime.STRING_NA;
         } else {
-            return this.levels.getDataAt(vector.getDataAt(index) - 1);
+            int val = vector.getDataAt(index);
+            if (naCheck.check(val)) {
+                return RRuntime.STRING_NA;
+            } else {
+                String l = levels.getDataAt(val - 1);
+                if (naCheck.check(l)) {
+                    return "NA"; // for comparison
+                } else {
+                    return l;
+                }
+            }
         }
     }
 }
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 605937e8f3..558be5cd61 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
@@ -8310,6 +8310,14 @@ x
 [1,] 10+0i -4+0i
 [2,] -2+0i  0+0i
 
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ as.logical(factor(c("a", "b", "a"))) }
+[1] NA NA NA
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ as.logical(factor(integer())) }
+logical(0)
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{ x<-c("1","2","3"); class(x)<-"factor"; x }
 Error in class(x) <- "factor" :
@@ -8320,6 +8328,16 @@ Error in class(x) <- "factor" :
 Error in class(x) <- "factor" :
   adding class "factor" to an invalid object
 
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-c(1L, 2L, 1L); class(x)<-c("factor", "ordered"); levels(x)<-c("a", "b"); x > "a" }
+[1] NA NA NA
+Warning message:
+In Ops.factor(x, "a") : > not meaningful for factors
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-c(1L, 2L, 1L); class(x)<-c("ordered", "factor"); levels(x)<-c("a", "b"); x > "a" }
+[1] FALSE  TRUE FALSE
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{ x<-c(1L,2L,3L); class(x)<-"factor"; x }
 Error in print.factor(1:3) : replacement has length zero
@@ -8332,6 +8350,10 @@ NULL
 #{ x<-factor(c("a", "b", "a")); attr(x, "levels")<-character(); as.character(x) }
 [1] NA NA NA
 
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a")); is.atomic(x) }
+[1] TRUE
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{ x<-factor(c("a", "b", "a")); x == "a" }
 [1]  TRUE FALSE  TRUE
@@ -8387,6 +8409,14 @@ Levels: a b
 [1] a    b    a    <NA>
 Levels: a b
 
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a"), ordered=TRUE); is.atomic(x) }
+[1] TRUE
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a"), ordered=TRUE); x > "a" }
+[1] FALSE  TRUE FALSE
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{ x<-factor(c("a", "b", "a", "c")); x == c("a", "b") }
 [1]  TRUE  TRUE  TRUE FALSE
@@ -8398,6 +8428,10 @@ Warning message:
 In y[1] <- x :
   number of items to replace is not a multiple of replacement length
 
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("c", "b", "a", "c")); y<-c(1); y[[1]]<-x; y }
+Error in y[[1]] <- x : more elements supplied than there are to replace
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{ x<-factor(c("c", "b", "a", "c")); y<-list(1); y[1]<-x; y }
 [[1]]
@@ -8407,6 +8441,13 @@ Warning message:
 In y[1] <- x :
   number of items to replace is not a multiple of replacement length
 
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("c", "b", "a", "c")); y<-list(1); y[[1]]<-x; y }
+[[1]]
+[1] c b a c
+Levels: a b c
+
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{data = c(1,2,2,3,1,2,3,3,1,2,3,3,1);fdata<-factor(data);levels(fdata) = c('I','II','III');print(fdata);}
  [1] I   II  II  III I   II  III III I   II  III III I
@@ -16277,6 +16318,18 @@ $x
 2 33 bb
 3 55 cc
 
+##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testMisc
+#{ y<-data.frame(7); as.logical(y) }
+[1] TRUE
+
+##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testMisc
+#{ y<-data.frame(c(1,2,3)); as.logical(y) }
+Error: (list) object cannot be coerced to type 'logical'
+
+##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testMisc
+#{ y<-data.frame(integer()); as.logical(y) }
+[1] NA
+
 ##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testPrint
 #{ n = c(2, 3, 5); s = c(TRUE, FALSE, TRUE); df = data.frame(n, s); df }
   n     s
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java
index 7bd93077b9..fb90a257aa 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java
@@ -8123,6 +8123,21 @@ public class AllTests extends TestBase {
         assertEval("{ x<-factor(c(\"a\", \"b\", \"a\", \"c\")); x == c(\"a\", \"b\") }");
     }
 
+    @Test
+    public void TestSimpleBuiltins_testFactor_c6b2929aec56f236a9015269d6d5e6f0() {
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); x > \"a\" }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_e759d4fccb890277ccc9ddb8fcb0dec3() {
+        assertEval("{ x<-c(1L, 2L, 1L); class(x)<-c(\"ordered\", \"factor\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_9383599e2b32f549f5e46351c2e6bd9b() {
+        assertEval("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-list(1); y[[1]]<-x; y }");
+    }
+
     @Test
     public void TestSimpleBuiltins_testFactor_ef37cc56e92b1c4a3742f47b97df2525() {
         assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[1] }");
@@ -8153,6 +8168,26 @@ public class AllTests extends TestBase {
         assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[c(1,2,3,4)] }");
     }
 
+    @Test
+    public void TestSimpleBuiltins_testFactor_fdae08cc3544f4e5c971d2303a796eeb() {
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); is.atomic(x) }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_5302c7a50fda26503b5d1f681cec279c() {
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); is.atomic(x) }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_a8153cc5be539920818caa4f7d546190() {
+        assertEval("{ as.logical(factor(c(\"a\", \"b\", \"a\"))) }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_19ca5910d2b0103d936cfdd499387aa2() {
+        assertEval("{ as.logical(factor(integer())) }");
+    }
+
     @Test
     public void TestSimpleBuiltins_testFactor_2ef7de52def309425a9b70965111f004() {
         assertEvalError("{ x<-c(1,2,3); class(x)<-\"factor\"; x }");
@@ -8178,6 +8213,16 @@ public class AllTests extends TestBase {
         assertEvalError("{ x<-factor(c(\"a\", \"b\", \"a\")); x > c(\"a\", \"b\") }");
     }
 
+    @Test
+    public void TestSimpleBuiltins_testFactor_e1f4890b0e585468d589f92e64e8fe43() {
+        assertEvalError("{ x<-c(1L, 2L, 1L); class(x)<-c(\"factor\", \"ordered\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_778d87ada7ac057126f8a27cfe882a81() {
+        assertEvalError("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-c(1); y[[1]]<-x; y }");
+    }
+
     @Test
     public void TestSimpleBuiltins_testFactor_61bfd366e4db68e9bda18fe2c3cc87f2() {
         assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x == c(\"a\", \"b\") }");
@@ -17093,6 +17138,21 @@ public class AllTests extends TestBase {
         assertEval("{ n = c(2, 3, 5); s = c(\"aa\", \"bb\", \"cc\"); df = data.frame(n, s); df[[1]] <- c(22,33,55); df }");
     }
 
+    @Test
+    public void TestSimpleDataFrames_testMisc_e52a62b09e6557563b89aed7622a090f() {
+        assertEval("{ y<-data.frame(7); as.logical(y) }");
+    }
+
+    @Test
+    public void TestSimpleDataFrames_testMisc_41c31f4873ee11a67409c7646ea787b9() {
+        assertEval("{ y<-data.frame(integer()); as.logical(y) }");
+    }
+
+    @Test
+    public void TestSimpleDataFrames_testMisc_526983ed080a1f64591401d75eba5c80() {
+        assertEvalError("{ y<-data.frame(c(1,2,3)); as.logical(y) }");
+    }
+
     @Test
     public void TestSimpleDataFrames_testPrint_da9c92f6582f469a3303b14bf936c77e() {
         assertEval("{x<-c(1,2); class(x)<-\"data.frame\"; x}");
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java
index d66c062c8b..ac3cfff7ea 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java
@@ -3907,9 +3907,15 @@ public class TestSimpleBuiltins extends TestBase {
         assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x == c(\"a\", \"b\") }");
         assertEvalError("{ x<-factor(c(\"a\", \"b\", \"a\")); x > c(\"a\", \"b\") }");
         assertEval("{ x<-factor(c(\"a\", \"b\", \"a\", \"c\")); x == c(\"a\", \"b\") }");
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); x > \"a\" }");
+
+        assertEval("{ x<-c(1L, 2L, 1L); class(x)<-c(\"ordered\", \"factor\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }");
+        assertEvalError("{ x<-c(1L, 2L, 1L); class(x)<-c(\"factor\", \"ordered\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }");
 
         assertEvalWarning("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-list(1); y[1]<-x; y }");
         assertEvalWarning("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-c(1); y[1]<-x; y }");
+        assertEval("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-list(1); y[[1]]<-x; y }");
+        assertEvalError("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-c(1); y[[1]]<-x; y }");
 
         assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[1] }");
         assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[[1]] }");
@@ -3917,6 +3923,12 @@ public class TestSimpleBuiltins extends TestBase {
         assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[[2]] }");
         assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[c(1,2)] }");
         assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[c(1,2,3,4)] }");
+
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); is.atomic(x) }");
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); is.atomic(x) }");
+
+        assertEval("{ as.logical(factor(c(\"a\", \"b\", \"a\"))) }");
+        assertEval("{ as.logical(factor(integer())) }");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleDataFrames.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleDataFrames.java
index 8a9644e161..feb33af1ad 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleDataFrames.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleDataFrames.java
@@ -141,6 +141,11 @@ public class TestSimpleDataFrames extends TestBase {
     @Test
     public void testMisc() {
         assertEval("{ n = c(2, 3, 5); s = c(\"aa\", \"bb\", \"cc\"); df = data.frame(n, s); df[[1]] <- c(22,33,55); df }");
+
+        assertEval("{ y<-data.frame(7); as.logical(y) }");
+        assertEval("{ y<-data.frame(integer()); as.logical(y) }");
+        assertEvalError("{ y<-data.frame(c(1,2,3)); as.logical(y) }");
+
     }
 
 }
-- 
GitLab