diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
index a881407971880e04ca684dc1a66dd08129e1c4d9..ebf063b71dffefaff13aaf04a55a5eed6eb5f286 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
@@ -100,14 +100,14 @@ public class DynLoadFunctions {
                 data[i] = dllInfo;
             }
             RList result = RDataFactory.createList(data, RDataFactory.createStringVector(names, RDataFactory.COMPLETE_VECTOR));
-            RVector.setClassAttr(result, RDataFactory.createStringVectorFromScalar(DLLINFOLIST_CLASS), null, null);
+            RVector.setVectorClassAttr(result, RDataFactory.createStringVectorFromScalar(DLLINFOLIST_CLASS), null, null);
             return result;
         }
     }
 
     private static RList createDLLInfoList(Object[] data) {
         RList dllInfo = RDataFactory.createList(data, RDataFactory.createStringVector(DLLInfo.NAMES, RDataFactory.COMPLETE_VECTOR));
-        RVector.setClassAttr(dllInfo, RDataFactory.createStringVectorFromScalar(DLLINFO_CLASS), null, null);
+        RVector.setVectorClassAttr(dllInfo, RDataFactory.createStringVectorFromScalar(DLLINFO_CLASS), null, null);
         return dllInfo;
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
index efa2d560ffd323ac0cb5ded1a4fdb5334c039087..9edbd53f30eb6535a8aad7e37eed72c8a606666b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
@@ -314,7 +314,7 @@ public class LaFunctions {
             RDoubleVector modulusVec = RDataFactory.createDoubleVectorFromScalar(modulus);
             modulusVec.setAttr("logarithm", useLogIn);
             RList result = RDataFactory.createList(new Object[]{modulusVec, sign}, NAMES_VECTOR);
-            RList.setClassAttr(result, DET_CLASS, null, null);
+            RList.setVectorClassAttr(result, DET_CLASS, null, null);
             return result;
         }
     }
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 4ffba92c5db28e803805d63af15646fb62857e07..fcc23b4d159c2eac5ce04b236226bdf2fad83153 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
@@ -79,10 +79,18 @@ public abstract class Structure extends RBuiltinNode {
         for (int i = 0; i < values.length; i++) {
             Object value = fixupValue(values[i]);
             String attrName = fixupAttrName(argNames[i + 1]);
-            if (value == RNull.instance) {
-                res.removeAttr(attrName);
+            if (attrName.equals(RRuntime.CLASS_ATTR_KEY)) {
+                if (value == RNull.instance) {
+                    res = (RAbstractContainer) res.setClassAttr(null);
+                } else {
+                    res = (RAbstractContainer) res.setClassAttr((RStringVector) value);
+                }
             } else {
-                res = (RAbstractContainer) res.setAttr(attrName, value);
+                if (value == RNull.instance) {
+                    res.removeAttr(attrName);
+                } else {
+                    res.setAttr(attrName, value);
+                }
             }
         }
         return res;
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 b00fa7944d4bfffbc4132821061510cf078301a9..78aa089824addcc4edd5c63a273d83dc567247cc 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,7 +164,7 @@ public abstract class TypeConvert extends RBuiltinNode {
             }
             RIntVector res = RDataFactory.createIntVector(data, complete);
             res.setLevels(RDataFactory.createStringVector(levelsArray, RDataFactory.COMPLETE_VECTOR));
-            return RVector.setClassAttr(res, RDataFactory.createStringVector("factor"), null, null);
+            return RVector.setVectorClassAttr(res, RDataFactory.createStringVector("factor"), null, null);
         }
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java
index eb31cd844a3b507e5dbdc44ca31776eb3da61af2..e5cf9deda213d3b50990031152b8629995aad884 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java
@@ -35,7 +35,7 @@ public abstract class UnClass extends RBuiltinNode {
             if (resultVector.isShared()) {
                 resultVector = resultVector.copy();
             }
-            return RVector.setClassAttr(resultVector, null, null, null);
+            return RVector.setVectorClassAttr(resultVector, null, null, null);
         }
         return arg;
     }
@@ -48,7 +48,7 @@ public abstract class UnClass extends RBuiltinNode {
         if (resultFrame.isShared()) {
             resultFrame = resultFrame.copy();
         }
-        return RVector.setClassAttr(resultFrame.getVector(), null, arg, null);
+        return RVector.setVectorClassAttr(resultFrame.getVector(), null, arg, null);
     }
 
     @Specialization
@@ -59,6 +59,6 @@ public abstract class UnClass extends RBuiltinNode {
         if (resultFrame.isShared()) {
             resultFrame = resultFrame.copy();
         }
-        return RVector.setClassAttr(resultFrame.getVector(), null, null, arg);
+        return RVector.setVectorClassAttr(resultFrame.getVector(), null, null, arg);
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
index 9cc09ec1e4d84395cd5dea0798e1d1c1645ca325..5dc2897803a17a4a35e0067229a1fd98cc115e64 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
@@ -99,7 +99,7 @@ public abstract class UpdateAttr extends RInvisibleBuiltinNode {
         } else if (name.equals(RRuntime.DIMNAMES_ATTR_KEY)) {
             return updateDimNames(frame, resultVector, value);
         } else if (name.equals(RRuntime.CLASS_ATTR_KEY)) {
-            return RVector.setClassAttr(resultVector, null, container.getElementClass() == RDataFrame.class ? container : null, container.getElementClass() == RFactor.class ? container : null);
+            return RVector.setVectorClassAttr(resultVector, null, container.getElementClass() == RDataFrame.class ? container : null, container.getElementClass() == RFactor.class ? container : null);
         } else if (name.equals(RRuntime.ROWNAMES_ATTR_KEY)) {
             resultVector.setRowNames(null);
         } else if (name.equals(RRuntime.LEVELS_ATTR_KEY)) {
@@ -114,11 +114,11 @@ public abstract class UpdateAttr extends RInvisibleBuiltinNode {
     @TruffleBoundary
     public static RAbstractContainer setClassAttrFromObject(RVector resultVector, RAbstractContainer container, Object value, SourceSection sourceSection) {
         if (value instanceof RStringVector) {
-            return RVector.setClassAttr(resultVector, (RStringVector) value, container.getElementClass() == RDataFrame.class ? container : null,
+            return RVector.setVectorClassAttr(resultVector, (RStringVector) value, container.getElementClass() == RDataFrame.class ? container : null,
                             container.getElementClass() == RFactor.class ? container : null);
         }
         if (value instanceof String) {
-            return RVector.setClassAttr(resultVector, RDataFactory.createStringVector((String) value), container.getElementClass() == RDataFrame.class ? container : null,
+            return RVector.setVectorClassAttr(resultVector, RDataFactory.createStringVector((String) value), container.getElementClass() == RDataFrame.class ? container : null,
                             container.getElementClass() == RFactor.class ? container : null);
         }
         throw RError.error(sourceSection, RError.Message.SET_INVALID_CLASS_ATTR);
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 196a22df5bacf0f424000ad8a99e35d88d83016b..1026beea51f893fae726a59c2c250392da7d0f44 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
@@ -176,7 +176,7 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode {
                 }
             } else if (attrName.equals(RRuntime.CLASS_ATTR_KEY)) {
                 if (value == RNull.instance) {
-                    res = RVector.setClassAttr(resultVector, null, container.getElementClass() == RDataFrame.class ? container : null, container.getElementClass() == RFactor.class ? container : null);
+                    res = RVector.setVectorClassAttr(resultVector, null, container.getElementClass() == RDataFrame.class ? container : null, container.getElementClass() == RFactor.class ? container : null);
                 } else {
                     res = UpdateAttr.setClassAttrFromObject(resultVector, container, value, getEncapsulatingSourceSection());
                 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
index b3675f366db369c158ec27d7f1b2bf98afc7e8bc..37fa0e9d465ea96cd68cb0f540b5e68ec3131a63 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
@@ -61,7 +61,7 @@ public abstract class UpdateClass extends RBuiltinNode {
     protected Object setClass(RAbstractContainer arg, @SuppressWarnings("unused") RNull className) {
         controlVisibility();
         RVector resultVector = arg.materializeNonSharedVector();
-        return RVector.setClassAttr(resultVector, null, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
+        return RVector.setVectorClassAttr(resultVector, null, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
     }
 
     @Specialization
@@ -102,7 +102,7 @@ public abstract class UpdateClass extends RBuiltinNode {
             throw RError.error(getEncapsulatingSourceSection(), RError.Message.NOT_ARRAY_UPDATE_CLASS);
         }
 
-        return RVector.setClassAttr(resultVector, RDataFactory.createStringVector(className), arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg
+        return RVector.setVectorClassAttr(resultVector, RDataFactory.createStringVector(className), arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg
                         : null);
     }
 
@@ -111,7 +111,7 @@ public abstract class UpdateClass extends RBuiltinNode {
     protected Object setClass(RAbstractContainer arg, RStringVector className) {
         controlVisibility();
         RVector resultVector = arg.materializeNonSharedVector();
-        return RVector.setClassAttr(resultVector, className, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
+        return RVector.setVectorClassAttr(resultVector, className, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
     }
 
     public Object setClass(RFunction arg, @SuppressWarnings("unused") Object className) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
index c9d49853b917dadec1fc28443c79387dd7185d5e..bda5ebe634a64bbaaee2959a01c772c0840c4129 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
@@ -76,7 +76,7 @@ public abstract class UpdateOldClass extends RInvisibleBuiltinNode {
     protected Object setOldClass(RAbstractContainer arg, RStringVector className) {
         controlVisibility();
         RVector resultVector = arg.materializeNonSharedVector();
-        return RVector.setClassAttr(resultVector, className, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
+        return RVector.setVectorClassAttr(resultVector, className, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
     }
 
     @Specialization
@@ -84,7 +84,7 @@ public abstract class UpdateOldClass extends RInvisibleBuiltinNode {
     protected Object setOldClass(RAbstractContainer arg, @SuppressWarnings("unused") RNull className) {
         controlVisibility();
         RVector resultVector = arg.materializeNonSharedVector();
-        return RVector.setClassAttr(resultVector, null, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
+        return RVector.setVectorClassAttr(resultVector, null, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
     }
 
     @TruffleBoundary
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 9203dd89db409b1e40366e494b344bdbc3074028..480169c013a924a88259accdc8287cd4048fb1a9 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,17 @@ public abstract class UpdateStorageMode extends RBuiltinNode {
                     if (attrs != null) {
                         RAttributable rresult = (RAttributable) result;
                         for (RAttribute attr : attrs) {
-                            rresult = rresult.setAttr(attr.getName(), attr.getValue());
+                            String attrName = attr.getName();
+                            Object v = attr.getValue();
+                            if (attrName.equals(RRuntime.CLASS_ATTR_KEY)) {
+                                if (v == RNull.instance) {
+                                    rresult = rresult.setClassAttr(null);
+                                } else {
+                                    rresult = rresult.setClassAttr((RStringVector) v);
+                                }
+                            } else {
+                                rresult.setAttr(attrName, v);
+                            }
                         }
                     }
                 }
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 623bd07b9de50c87d9be1853181a41ebeb9407b3..42cc3f0d73727ff0f766e5231a30dc66ca76f5c1 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,7 +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));
-        return RVector.setClassAttr(res, RDataFactory.createStringVector("factor"), null, null);
+        return RVector.setVectorClassAttr(res, RDataFactory.createStringVector("factor"), null, null);
     }
 
     @SuppressWarnings("unused")
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
index 3b2e1647c639918a561c3c1d97aafa85331bdc0f..ca31defef717cb4c7268e3c49f94a3b39e86a222 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
@@ -88,6 +88,28 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode {
         return specializeToUnaryOp().execute(frame, left);
     }
 
+    @Specialization
+    protected RLogicalVector doFactorOp(RFactor left, @SuppressWarnings("unused") RNull right) {
+        if (left.isOrdered()) {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_ORDERED_FACTORS, arithmetic.opName());
+
+        } else {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, arithmetic.opName());
+        }
+        return RDataFactory.createNAVector(left.getLength() == 0 ? 1 : left.getLength());
+    }
+
+    @Specialization
+    protected RLogicalVector doFactorOp(@SuppressWarnings("unused") RNull left, RFactor right) {
+        if (right.isOrdered()) {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_ORDERED_FACTORS, arithmetic.opName());
+
+        } else {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, arithmetic.opName());
+        }
+        return RDataFactory.createNAVector(right.getLength() == 0 ? 1 : right.getLength());
+    }
+
     @Specialization
     protected RDoubleVector doLeftNull(RNull left, RAbstractIntVector right) {
         return doRightNull(right, left);
@@ -103,6 +125,12 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode {
         return doRightNull(right, left);
     }
 
+    @SuppressWarnings("unused")
+    @Specialization(guards = "nonNumeric")
+    protected RComplexVector doLeftNull(RNull left, RAbstractVector right) {
+        throw RError.error(this.getSourceSection(), RError.Message.NON_NUMERIC_BINARY);
+    }
+
     @Specialization
     protected RComplexVector doLeftNull(RNull left, RAbstractComplexVector right) {
         return doRightNull(right, left);
@@ -132,31 +160,37 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode {
         return RDataFactory.createEmptyComplexVector();
     }
 
+    @SuppressWarnings("unused")
+    @Specialization(guards = "nonNumeric")
+    protected RComplexVector doRightNull(RAbstractVector left, RNull right) {
+        throw RError.error(this.getSourceSection(), RError.Message.NON_NUMERIC_BINARY);
+    }
+
     @SuppressWarnings("unused")
     @Specialization
     protected RDoubleVector doRightNull(RNull left, RNull right) {
         return RDataFactory.createEmptyDoubleVector();
     }
 
-    @Specialization
-    protected Object doLeftString(RAbstractStringVector left, Object right) {
+    @Specialization(guards = "!isFactorRight")
+    protected Object doLeftString(RAbstractStringVector left, RAbstractContainer right) {
         return doRightString(right, left);
     }
 
     @SuppressWarnings("unused")
-    @Specialization
-    protected Object doRightString(Object left, RAbstractStringVector right) {
+    @Specialization(guards = "!isFactorLeft")
+    protected Object doRightString(RAbstractContainer left, RAbstractStringVector right) {
         throw RError.error(this.getSourceSection(), RError.Message.NON_NUMERIC_BINARY);
     }
 
-    @Specialization
-    protected Object doLeftRaw(RAbstractRawVector left, Object right) {
+    @Specialization(guards = "!isFactorRight")
+    protected Object doLeftRaw(RAbstractRawVector left, RAbstractContainer right) {
         return doRightRaw(right, left);
     }
 
     @SuppressWarnings("unused")
-    @Specialization
-    protected Object doRightRaw(Object left, RAbstractRawVector right) {
+    @Specialization(guards = "!isFactorLeft")
+    protected Object doRightRaw(RAbstractContainer left, RAbstractRawVector right) {
         throw RError.error(this.getSourceSection(), RError.Message.NON_NUMERIC_BINARY);
     }
 
@@ -490,6 +524,50 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode {
         return performComplexVectorOpSameLength(left, right);
     }
 
+    // factors
+
+    @Specialization
+    protected RLogicalVector doFactorOp(RFactor left, RAbstractContainer right) {
+        if (left.isOrdered()) {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_ORDERED_FACTORS, arithmetic.opName());
+
+        } else {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, arithmetic.opName());
+        }
+        return RDataFactory.createNAVector(Math.max(left.getLength(), right.getLength()));
+    }
+
+    @Specialization
+    protected RLogicalVector doFactorOp(RAbstractContainer left, RFactor right) {
+        if (right.isOrdered()) {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_ORDERED_FACTORS, arithmetic.opName());
+
+        } else {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, arithmetic.opName());
+        }
+        return RDataFactory.createNAVector(Math.max(left.getLength(), right.getLength()));
+    }
+
+    protected boolean nonNumeric(@SuppressWarnings("unused") RNull left, RAbstractContainer right) {
+        return right.getElementClass() == RString.class || right.getElementClass() == RRaw.class;
+    }
+
+    protected boolean nonNumeric(RAbstractContainer left) {
+        return left.getElementClass() == RString.class || left.getElementClass() == RRaw.class;
+    }
+
+    protected boolean isFactorLeft(RAbstractContainer left) {
+        return left.getElementClass() == RFactor.class;
+    }
+
+    protected boolean isFactorRight(@SuppressWarnings("unused") RAbstractStringVector left, RAbstractContainer right) {
+        return right.getElementClass() == RFactor.class;
+    }
+
+    protected boolean isFactorRight(@SuppressWarnings("unused") RAbstractRawVector left, RAbstractContainer right) {
+        return right.getElementClass() == RFactor.class;
+    }
+
     // implementation
 
     private void copyAttributes(RVector ret, RAbstractVector left, RAbstractVector right) {
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 d1a4c5b129a9ca0b5bab5b66048f2aee13705b18..40bec6926fa771ed92988b51ca2b2782a1a1ffd0 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
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.nodes.binary;
 
+import java.util.*;
+
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
@@ -293,12 +295,39 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
     // null
 
     @Specialization
-    protected RLogicalVector doNull(RNull left, Object right) {
+    protected RLogicalVector doNull(RNull left, RNull right) {
         return RDataFactory.createLogicalVector(0);
     }
 
-    @Specialization
-    protected RLogicalVector doNull(Object left, RNull right) {
+    @Specialization(guards = "!isFactor")
+    protected RLogicalVector doNull(RNull left, RAbstractContainer right) {
+        return RDataFactory.createLogicalVector(0);
+    }
+
+    @Specialization(guards = "!isFactor")
+    protected RLogicalVector doNull(RAbstractContainer left, RNull right) {
+        return RDataFactory.createLogicalVector(0);
+    }
+
+    @Specialization(guards = "!meaningfulOp")
+    protected RLogicalVector doFactorOpError(RFactor left, RNull right) {
+        RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
+        return RDataFactory.createNAVector(left.getLength() == 0 ? 1 : left.getLength());
+    }
+
+    @Specialization(guards = "!meaningfulOp")
+    protected RLogicalVector doFactorOpError(RNull left, RFactor right) {
+        RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
+        return RDataFactory.createNAVector(right.getLength() == 0 ? 1 : right.getLength());
+    }
+
+    @Specialization(guards = "meaningfulOp")
+    protected RLogicalVector doFactorOp(RFactor left, RNull right) {
+        return RDataFactory.createLogicalVector(0);
+    }
+
+    @Specialization(guards = "meaningfulOp")
+    protected RLogicalVector doFactorOp(RNull left, RFactor right) {
         return RDataFactory.createLogicalVector(0);
     }
 
@@ -703,16 +732,6 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
 
     // factor and scalar
 
-    @Specialization(guards = "!meaningfulOp")
-    protected RLogicalVector doFactorOp(RFactor left, Object right) {
-        throw RError.error(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
-    }
-
-    @Specialization(guards = "!meaningfulOp")
-    protected RLogicalVector doFactorOp(Object left, RFactor right) {
-        throw RError.error(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
-    }
-
     @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, int right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.intToString(right, false), false);
@@ -1251,6 +1270,18 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
         return performStringVectorOpSameLength(RClosures.createRawToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
+    @Specialization(guards = "!meaningfulOp")
+    protected RLogicalVector doFactorOp(RFactor left, RAbstractContainer right) {
+        RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
+        return RDataFactory.createNAVector(Math.max(left.getLength(), right.getLength()));
+    }
+
+    @Specialization(guards = "!meaningfulOp")
+    protected RLogicalVector doFactorOp(RAbstractContainer left, RFactor right) {
+        RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
+        return RDataFactory.createNAVector(Math.max(left.getLength(), right.getLength()));
+    }
+
     // complex vector and vectors
 
     @Specialization(guards = "!areSameLength")
@@ -1338,10 +1369,42 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
 
     // guards
 
+    public boolean isFactor(RAbstractContainer left, RNull right) {
+        return left.getElementClass() == RFactor.class;
+    }
+
+    public boolean isFactor(RNull left, RAbstractContainer right) {
+        return right.getElementClass() == RFactor.class;
+    }
+
+    public boolean isFactor(RFactor left, RAbstractContainer right) {
+        return right.getElementClass() == RFactor.class;
+    }
+
+    public boolean isFactor(RAbstractContainer left, RFactor right) {
+        return left.getElementClass() == RFactor.class;
+    }
+
     public boolean meaningfulOp(RFactor left, RFactor right) {
         return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || (left.isOrdered() && right.isOrdered());
     }
 
+    public boolean meaningfulOp(RFactor left, RNull right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || left.isOrdered();
+    }
+
+    public boolean meaningfulOp(RNull left, RFactor right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || right.isOrdered();
+    }
+
+    public boolean meaningfulOp(RFactor left, RAbstractContainer right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || left.isOrdered();
+    }
+
+    public boolean meaningfulOp(RAbstractContainer left, RFactor right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || right.isOrdered();
+    }
+
     public boolean meaningfulOp(RFactor left, Object right) {
         return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || left.isOrdered();
     }
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 c5ad5fba8bd9cd6ff01f9fa949957950c2136c28..6e4f3226d39803fb3761b6179238b3d33db7c912 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
@@ -557,7 +557,8 @@ public final class RError extends RuntimeException {
         DEFAULT_METHOD_NOT_IMPLEMENTED_FOR_TYPE("default method not implemented for type '%s'"),
         ADDING_INVALID_CLASS("adding class \"%s\" to an invalid object"),
         IS_NA_TO_NON_VECTOR("is.na() applied to non-(list or vector) of type '%s'"),
-        NOT_MEANINGFUL_FOR_FACTORS("%s not meaningful for factors");
+        NOT_MEANINGFUL_FOR_FACTORS("%s not meaningful for factors"),
+        NOT_MEANINGFUL_FOR_ORDERED_FACTORS("'%s' is not meaningful for ordered factors");
 
         public final String message;
         private final boolean hasArgs;
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 30a6913553da083103bab1a31ae34fb27073b5a3..e2f49ac88dcbb020b042f773dd469427bde058a0 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)) {
-                        result = RVector.setClassAttr(vec, (RStringVector) car, null, null);
+                        result = RVector.setVectorClassAttr(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 3c51b93d1bdb1b184c2ed7f8a582bd5c9f25ada1..4b795f9d393c001b004791d4978f971340937459 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
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.data;
 
+import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.env.*;
 
 /**
@@ -48,13 +49,12 @@ 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.
      */
-    default RAttributable setAttr(String name, Object value) {
+    default void setAttr(String name, Object value) {
         RAttributes attributes = getAttributes();
         if (attributes == null) {
             attributes = initAttributes();
         }
         attributes.put(name, value);
-        return this;
     }
 
     /**
@@ -67,4 +67,10 @@ public interface RAttributable {
             attributes.remove(name);
         }
     }
+
+    default RAttributable setClassAttr(RStringVector classAttr) {
+        setAttr(RRuntime.CLASS_ATTR_KEY, classAttr);
+        return this;
+    }
+
 }
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 1d19b5ae62deca786f9453d6ee25f403671f57a7..8c8f02ad26173dd8b5ff47c9e03392259e47dafc 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
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.runtime.data;
 
+import java.util.*;
+
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.RPromise.Closure;
@@ -176,6 +178,12 @@ public final class RDataFactory {
         return traceDataCreated(new RLogicalVector(data, complete, dims, names));
     }
 
+    public static RLogicalVector createNAVector(int length) {
+        byte[] data = new byte[length];
+        Arrays.fill(data, RRuntime.LOGICAL_NA);
+        return createLogicalVector(data, INCOMPLETE_VECTOR);
+    }
+
     public static RIntSequence createAscendingRange(int start, int end) {
         assert start <= end;
         return traceDataCreated(new RIntSequence(start, 1, end - start + 1));
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFrame.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFrame.java
index 3937de107a4e864f4215721134aa08ab12d1f853..41d6acbfbe38c1d2413e27f4028c8e0964754098 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFrame.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFrame.java
@@ -142,4 +142,9 @@ public final class RDataFrame implements RShareable, RAbstractContainer {
         return vector.getElementIndexByNameInexact(name);
     }
 
+    @Override
+    public RAbstractContainer setClassAttr(RStringVector classAttr) {
+        return RVector.setVectorClassAttr(vector, classAttr, this, null);
+    }
+
 }
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 600a7da4eef815eb085e2042803f08b597b23677..95330a9bb1f29368496be5893f746564e9f94bec 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
@@ -153,4 +153,9 @@ public final class RFactor implements RShareable, RAbstractContainer {
         vector.setLevels(newLevels);
     }
 
+    @Override
+    public RAbstractContainer setClassAttr(RStringVector classAttr) {
+        return RVector.setVectorClassAttr(vector, classAttr, null, this);
+    }
+
 }
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 2b3a6961a4c433cc51504cf0b79f2757fa692df2..50e8e7f91f8bbd6391aafc4ffa6a4c805809ccc2 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,11 +163,10 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
     }
 
     @TruffleBoundary
-    public final RAbstractContainer setAttr(String name, Object value) {
+    public final void 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)) {
@@ -181,11 +180,10 @@ 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)) {
-            res = setClassAttr(this, (RStringVector) value, null, null);
+            throw Utils.nyi("The \"class\" attribute should be set using a separate method");
         } else {
             attributes.put(name, value);
         }
-        return res;
     }
 
     public final Object getAttr(String name) {
@@ -206,7 +204,7 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
             } else if (name.equals(RRuntime.ROWNAMES_ATTR_KEY)) {
                 setRowNames(null);
             } else if (name.equals(RRuntime.CLASS_ATTR_KEY)) {
-                setClassAttr(this, (RStringVector) null, null, null);
+                throw Utils.nyi("The \"class\" attribute should be reset using a separate method");
             } else {
                 attributes.remove(name);
             }
@@ -398,13 +396,22 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
         }
     }
 
-    public static RAbstractContainer setClassAttr(RVector vector, RStringVector classAttr, RAbstractContainer enclosingDataFrame, RAbstractContainer enclosingFactor) {
+    @Override
+    public RAbstractContainer setClassAttr(RStringVector classAttr) {
+        return setClassAttrInternal(this, classAttr, null, null, true);
+    }
+
+    public static RAbstractContainer setVectorClassAttr(RVector vector, RStringVector classAttr, RAbstractContainer enclosingDataFrame, RAbstractContainer enclosingFactor) {
+        return setClassAttrInternal(vector, classAttr, enclosingDataFrame, enclosingFactor, false);
+    }
+
+    private static RAbstractContainer setClassAttrInternal(RVector vector, RStringVector classAttr, RAbstractContainer enclosingDataFrame, RAbstractContainer enclosingFactor, boolean convertToInt) {
         if (vector.attributes == null && classAttr != null && classAttr.getLength() != 0) {
             vector.initAttributes();
         }
         if (vector.attributes != null && (classAttr == null || classAttr.getLength() == 0)) {
             vector.removeAttributeMapping(RRuntime.CLASS_ATTR_KEY);
-            // class attribute removed - no longer a data frame (even if it was before)
+            // class attribute removed - no longer a data frame or factor (even if it was before)
             return vector;
         } else if (classAttr != null && classAttr.getLength() != 0) {
             boolean ordered = false;
@@ -425,17 +432,30 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
                         return RDataFactory.createDataFrame(vector);
                     }
                 } 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");
-                    }
                     vector.putAttribute(RRuntime.CLASS_ATTR_KEY, classAttr);
                     if (enclosingFactor != null) {
                         // was a factor and still is a factor
                         return enclosingFactor;
                     } else {
+                        RIntVector resVector;
+                        if (vector.getElementClass() != RInt.class) {
+                            if (vector.getElementClass() == RDouble.class && convertToInt) {
+                                RAbstractDoubleVector sourceVector = (RAbstractDoubleVector) vector;
+                                int[] data = new int[sourceVector.getLength()];
+                                for (int j = 0; j < data.length; j++) {
+                                    data[j] = RRuntime.double2int(sourceVector.getDataAt(j));
+                                }
+                                resVector = RDataFactory.createIntVector(data, sourceVector.isComplete());
+                                resVector.copyAttributesFrom(sourceVector);
+                            } else {
+                                // TODO: add source section
+                                throw RError.error(null, RError.Message.ADDING_INVALID_CLASS, "factor");
+                            }
+                        } else {
+                            resVector = (RIntVector) vector;
+                        }
                         // it's a factor now
-                        return RDataFactory.createFactor((RIntVector) vector, ordered);
+                        return RDataFactory.createFactor(resVector, ordered);
                     }
                 }
             }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java
index 1f7a32abe1f2513ef3e05c616dc5e8c7d9425a7e..bc37448c2807ca0676a435d9682e58efc4baffbd 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java
@@ -136,6 +136,8 @@ public abstract class BinaryArithmetic extends Operation {
         return supportsIntResult;
     }
 
+    public abstract String opName();
+
     public abstract int op(int left, int right);
 
     public abstract double op(double left, double right);
@@ -178,6 +180,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(true, true, true);
         }
 
+        @Override
+        public String opName() {
+            return "+";
+        }
+
         @Override
         public int op(int left, int right) {
             try {
@@ -227,6 +234,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(false, false, true);
         }
 
+        @Override
+        public String opName() {
+            return "-";
+        }
+
         @Override
         public int op(int left, int right) {
             try {
@@ -275,6 +287,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(true, true, true);
         }
 
+        @Override
+        public String opName() {
+            return "*";
+        }
+
         @Override
         public int op(int left, int right) {
             try {
@@ -398,6 +415,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(false, false, false);
         }
 
+        @Override
+        public String opName() {
+            return "/";
+        }
+
         @Override
         public final int op(int left, int right) {
             throw RInternalError.shouldNotReachHere();
@@ -470,6 +492,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(false, false, true);
         }
 
+        @Override
+        public String opName() {
+            return "%/%";
+        }
+
         @Override
         public int op(int left, int right) {
             if (right != 0) {
@@ -510,6 +537,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(false, false, true);
         }
 
+        @Override
+        public String opName() {
+            return "%%";
+        }
+
         @Override
         public int op(int left, int right) {
             // LICENSE: transcribed code from GNU R, which is licensed under GPL
@@ -552,6 +584,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(false, false, false);
         }
 
+        @Override
+        public String opName() {
+            return "^";
+        }
+
         @Override
         public int op(int left, int right) {
             throw RInternalError.shouldNotReachHere();
@@ -951,6 +988,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(true, true, true);
         }
 
+        @Override
+        public String opName() {
+            throw Utils.nyi();
+        }
+
         @Override
         public int op(int left, int right) {
             return Math.max(left, right);
@@ -980,6 +1022,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(true, true, true);
         }
 
+        @Override
+        public String opName() {
+            throw Utils.nyi();
+        }
+
         @Override
         public int op(int left, int right) {
             return Math.min(left, right);
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 558be5cd61f64004d60fc7c4133659a96a3c103f..b5bd69a3358855ede2050fbc927e0d09c3cd2b57 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
@@ -8328,12 +8328,24 @@ 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("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] NA NA NA
+Warning message:
+In Ops.ordered(x, "a") : '+' is not meaningful for ordered 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
@@ -8354,6 +8366,18 @@ NULL
 #{ 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] NA NA NA
+Warning message:
+In Ops.factor(x, "a") : + not meaningful for factors
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a")); x + c("a", "b") }
+[1] NA NA NA
+Warning message:
+In Ops.factor(x, c("a", "b")) : + not meaningful for factors
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{ x<-factor(c("a", "b", "a")); x == "a" }
 [1]  TRUE FALSE  TRUE
@@ -8413,6 +8437,12 @@ Levels: a b
 #{ 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] NA NA NA
+Warning message:
+In Ops.ordered(x, "a") : '+' is not meaningful for ordered factors
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{ x<-factor(c("a", "b", "a"), ordered=TRUE); x > "a" }
 [1] FALSE  TRUE FALSE
@@ -8448,6 +8478,45 @@ In y[1] <- x :
 Levels: a b c
 
 
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(c(1,2,1), .Label=c("a", "b"), class = c('factor'), .Names=c("111","112","113")); y<-structure(c(1,2,1), .Label=c("a", "b"), class = c('factor'), .Names=c("111","112","113")); x+y }
+[1] NA NA NA
+Warning message:
+In Ops.factor(x, y) : + not meaningful for factors
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(c(1,2,1), .Label=c("a", "b"), class = c('factor'), .Names=c("111","112","113")); y<-structure(c(1,2,1), .Label=c("a", "b"), class = c('factor'), .Names=c("111","112","113")); x==y }
+[1] TRUE TRUE TRUE
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(c(1.1,2.2,1.1), .Label=c("a", "b"), class = c('factor')); attributes(x) }
+$levels
+[1] "a" "b"
+
+$class
+[1] "factor"
+
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(c(1.1,2.2,1.1), .Label=c("a", "b"), class = c('factor')); x }
+[1] a b a
+Levels: a b
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(c(1.2,2.2,1.1), .Label=c("a", "b"), class = c('factor')); x }
+[1] a b a
+Levels: a b
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(c(2.2,3.2,2.1), .Label=c("a", "b"), class = c('factor')); as.integer(x) }
+[1] 2 3 2
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(factor(c("a","b","c")), class=NULL); x }
+[1] 1 2 3
+attr(,"levels")
+[1] "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
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 fb90a257aa2c0a196b13915fd21227016427c9ad..8f01be576944eb9643b8fc995eddac77bfe819fc 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
@@ -8188,6 +8188,36 @@ public class AllTests extends TestBase {
         assertEval("{ as.logical(factor(integer())) }");
     }
 
+    @Test
+    public void TestSimpleBuiltins_testFactor_efa5f97d32564f78732db53e6862362e() {
+        assertEval("{ x<-structure(c(1.1,2.2,1.1), .Label=c(\"a\", \"b\"), class = c('factor')); attributes(x) }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_d5fd844e772c2e96c1266f8c4e181e7a() {
+        assertEval("{ x<-structure(c(1.1,2.2,1.1), .Label=c(\"a\", \"b\"), class = c('factor')); x }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_69974a637dd01d933a0274513b334646() {
+        assertEval("{ x<-structure(c(1.2,2.2,1.1), .Label=c(\"a\", \"b\"), class = c('factor')); x }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_1d6da35b510c64fda496cd4d92b0b8dd() {
+        assertEval("{ x<-structure(c(2.2,3.2,2.1), .Label=c(\"a\", \"b\"), class = c('factor')); as.integer(x) }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_c97bd5071d6a70f07678a33414644e52() {
+        assertEval("{ x<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); y<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); x==y }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_a87228cb9283d7ba484ab0b60059e1bf() {
+        assertEval("{ x<-structure(factor(c(\"a\",\"b\",\"c\")), class=NULL); x }");
+    }
+
     @Test
     public void TestSimpleBuiltins_testFactor_2ef7de52def309425a9b70965111f004() {
         assertEvalError("{ x<-c(1,2,3); class(x)<-\"factor\"; x }");
@@ -8203,29 +8233,54 @@ public class AllTests extends TestBase {
         assertEvalError("{ x<-c(1L,2L,3L); class(x)<-\"factor\"; x }");
     }
 
+    @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_8e866be378d6495f8d649996dcb5bb3c() {
-        assertEvalError("{ x<-factor(c(\"a\", \"b\", \"a\")); x > \"a\" }");
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x > \"a\" }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_cab09968ee0783bc157730e05358ed0c() {
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x + \"a\" }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_61bfd366e4db68e9bda18fe2c3cc87f2() {
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x == c(\"a\", \"b\") }");
     }
 
     @Test
     public void TestSimpleBuiltins_testFactor_7cd2b27121f6c77b417a436d60108819() {
-        assertEvalError("{ x<-factor(c(\"a\", \"b\", \"a\")); x > c(\"a\", \"b\") }");
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x > c(\"a\", \"b\") }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_a34678ac5082e00e15dd97ecd53f0e12() {
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x + c(\"a\", \"b\") }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_7b9d1da1c475fe180c3d19653a62003e() {
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); x + \"a\" }");
     }
 
     @Test
     public void TestSimpleBuiltins_testFactor_e1f4890b0e585468d589f92e64e8fe43() {
-        assertEvalError("{ x<-c(1L, 2L, 1L); class(x)<-c(\"factor\", \"ordered\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }");
+        assertEvalWarning("{ 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 }");
+    public void TestSimpleBuiltins_testFactor_442949c79222d476ad19ed8d25f6d67b() {
+        assertEvalWarning("{ x<-c(1L, 2L, 1L); class(x)<-c(\"ordered\", \"factor\"); levels(x)<-c(\"a\", \"b\"); x + \"a\" }");
     }
 
     @Test
-    public void TestSimpleBuiltins_testFactor_61bfd366e4db68e9bda18fe2c3cc87f2() {
-        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x == c(\"a\", \"b\") }");
+    public void TestSimpleBuiltins_testFactor_b998c6b80f80df4ef39a60ff889bc0e4() {
+        assertEvalWarning("{ x<-c(1L, 2L, 1L); class(x)<-c(\"factor\", \"ordered\"); levels(x)<-c(\"a\", \"b\"); x + \"a\" }");
     }
 
     @Test
@@ -8238,6 +8293,11 @@ public class AllTests extends TestBase {
         assertEvalWarning("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-c(1); y[1]<-x; y }");
     }
 
+    @Test
+    public void TestSimpleBuiltins_testFactor_79abe62e1800fec0bdfb1ee89b43889b() {
+        assertEvalWarning("{ x<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); y<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); x+y }");
+    }
+
     @Test
     public void TestSimpleBuiltins_testFileListing_9646bfd3fb553824f1f54cc5d04b8219() {
         assertEval("{ list.files(\"test/r/simple/data/tree1\") }");
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 ac3cfff7ea8519702fb6b060f60527a0c48dd152..6de5fbfd62bc46f254fa9c5c7888d6f80aad9262 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
@@ -3902,15 +3902,20 @@ public class TestSimpleBuiltins extends TestBase {
         assertEvalError("{ x<-c(1L,2L,3L); class(x)<-\"factor\"; x }");
 
         assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x == \"a\" }");
-        assertEvalError("{ x<-factor(c(\"a\", \"b\", \"a\")); x > \"a\" }");
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x > \"a\" }");
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x + \"a\" }");
 
         assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x == c(\"a\", \"b\") }");
-        assertEvalError("{ x<-factor(c(\"a\", \"b\", \"a\")); x > c(\"a\", \"b\") }");
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x > c(\"a\", \"b\") }");
+        assertEvalWarning("{ 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\" }");
+        assertEvalWarning("{ 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<-c(1L, 2L, 1L); class(x)<-c(\"factor\", \"ordered\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }");
+        assertEvalWarning("{ x<-c(1L, 2L, 1L); class(x)<-c(\"ordered\", \"factor\"); levels(x)<-c(\"a\", \"b\"); x + \"a\" }");
+        assertEvalWarning("{ 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 }");
@@ -3929,6 +3934,17 @@ public class TestSimpleBuiltins extends TestBase {
 
         assertEval("{ as.logical(factor(c(\"a\", \"b\", \"a\"))) }");
         assertEval("{ as.logical(factor(integer())) }");
+
+        assertEval("{ x<-structure(c(1.1,2.2,1.1), .Label=c(\"a\", \"b\"), class = c('factor')); attributes(x) }");
+        assertEval("{ x<-structure(c(1.1,2.2,1.1), .Label=c(\"a\", \"b\"), class = c('factor')); x }");
+        assertEval("{ x<-structure(c(1.2,2.2,1.1), .Label=c(\"a\", \"b\"), class = c('factor')); x }");
+        assertEval("{ x<-structure(c(2.2,3.2,2.1), .Label=c(\"a\", \"b\"), class = c('factor')); as.integer(x) }");
+
+        assertEval("{ x<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); y<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); x==y }");
+        assertEvalWarning("{ x<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); y<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); x+y }");
+
+        assertEval("{ x<-structure(factor(c(\"a\",\"b\",\"c\")), class=NULL); x }");
+
     }
 
     @Test