diff --git a/com.oracle.truffle.r.native/library/lib.mk b/com.oracle.truffle.r.native/library/lib.mk index 085e5fa43163fc40ab8719348c9774235a3a1396..8de59dce0295f84495c1e14118d53a5a1c951620 100644 --- a/com.oracle.truffle.r.native/library/lib.mk +++ b/com.oracle.truffle.r.native/library/lib.mk @@ -89,6 +89,10 @@ $(C_OBJECTS): | $(OBJ) $(F_OBJECTS): | $(OBJ) +$(GNUR_C_OBJECTS): | $(OBJ) + +$(GNUR_F_OBJECTS): | $(OBJ) + $(OBJ): mkdir -p $(OBJ) diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java index 68f75c9d98b62dea975c220f8c92a37e9de3d75a..6a4c3ffe80e4766e1b38365708f2c744b64e06b4 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java @@ -30,6 +30,8 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.profiles.*; import com.oracle.truffle.r.nodes.builtin.*; +import com.oracle.truffle.r.nodes.control.SequenceNode; +import com.oracle.truffle.r.nodes.function.FunctionBodyNode; import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.data.*; import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute; @@ -156,6 +158,20 @@ public abstract class Identical extends RBuiltinNode { } RSyntaxNode xNode = x.getRep().asRSyntaxNode(); RSyntaxNode yNode = y.getRep().asRSyntaxNode(); + // the following is (at least) needed by setGeneric function which expects a call node + // and function body node containing a single (same) call node to be identical + if (xNode instanceof FunctionBodyNode) { + xNode = ((FunctionBodyNode) xNode).getStatements(); + } + if (yNode instanceof FunctionBodyNode) { + yNode = ((FunctionBodyNode) yNode).getStatements(); + } + if (xNode instanceof SequenceNode && ((SequenceNode) xNode).getSequence().length == 1) { + xNode = ((SequenceNode) xNode).getSequence()[0].asRSyntaxNode(); + } + if (yNode instanceof SequenceNode && ((SequenceNode) yNode).getSequence().length == 1) { + yNode = ((SequenceNode) yNode).getSequence()[0].asRSyntaxNode(); + } return RRuntime.asLogical(xNode.getRequalsImpl(yNode)); } return RRuntime.LOGICAL_FALSE; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java index 8548085db3135f95c5df12601582e4ec9c254c9f..89ac8adff35ecf324d816d1888350be296420676 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java @@ -41,9 +41,9 @@ import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.conn.StdConnections; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.data.RS4Object; import com.oracle.truffle.r.runtime.data.RTypedValue; public class PrintFunctions { @@ -102,7 +102,7 @@ public class PrintFunctions { // chacking for class attribute is a bit of a hack but GNU R has a hack in place here as // well to avoid recursively calling show via print in showDefault (we just can't use // the same hack at this point - for details see definition of showDefault in show.R) - return o instanceof RS4Object && ((RS4Object) o).getClassAttr(attrProfiles) != null; + return o instanceof RAttributable && ((RAttributable) o).isS4() && ((RAttributable) o).getClassAttr(attrProfiles) != 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 97c080069010e42467e5735b5fe86cb34d8bbd54..f02429010f90de132184f291f729592b38c7063d 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 @@ -110,11 +110,13 @@ public abstract class UnClass extends RBuiltinNode { objectProfile.enter(); // TODO: should we make S4 objects shareable? RS4Object resultS4 = RDataFactory.createS4Object(); - RAttributes newAttributes = resultS4.initAttributes(); - for (RAttribute attr : arg.getAttributes()) { - newAttributes.put(attr.getName(), attr.getValue()); + if (arg.getAttributes() != null) { + RAttributes newAttributes = resultS4.initAttributes(); + for (RAttribute attr : arg.getAttributes()) { + newAttributes.put(attr.getName(), attr.getValue()); + } + newAttributes.remove(RRuntime.CLASS_ATTR_KEY); } - newAttributes.remove(RRuntime.CLASS_ATTR_KEY); return resultS4; } return 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 b3456492ebd032b929d2ab2c9d53b6814a701c45..73952a707cdb3b48aed7a571118c6e2928b3d996 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 @@ -43,6 +43,7 @@ import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; @@ -196,13 +197,17 @@ public abstract class UpdateAttr extends RInvisibleBuiltinNode { * All other, non-performance centric, {@link RAttributable} types. */ @Fallback - protected Object updateAttr(Object object, Object name, Object value) { + protected Object updateAttr(Object obj, Object name, Object value) { + Object object = obj; controlVisibility(); String sname = RRuntime.asString(name); if (sname == null) { errorProfile.enter(); throw RError.error(this, RError.Message.MUST_BE_NONNULL_STRING, "name"); } + if (object instanceof RShareable) { + object = ((RShareable) object).getNonShared(); + } String internedName = intern(sname); if (object instanceof RAttributable) { RAttributable attributable = (RAttributable) object; 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 ef49e79dcf42cd57ec228d45c21a5f21ea24e40d..9acfb7ef6fa50094bbe2e272306833074ef06308 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 @@ -44,6 +44,7 @@ import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; @@ -209,8 +210,12 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode { */ @Fallback @TruffleBoundary - public Object doOther(Object obj, Object operand) { + public Object doOther(Object o, Object operand) { controlVisibility(); + Object obj = o; + if (obj instanceof RShareable) { + obj = ((RShareable) obj).getNonShared(); + } if (obj instanceof RAttributable) { RAttributable attrObj = (RAttributable) obj; attrObj.removeAllAttributes(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java index 0d1ccdf2568737c62788c0bbdc1404348fcaee65..938971c931d5d81dea6f63876f148ff9d15f02ba 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java @@ -17,7 +17,10 @@ import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.r.nodes.attributes.PutAttributeNode; import com.oracle.truffle.r.nodes.attributes.PutAttributeNodeGen; import com.oracle.truffle.r.nodes.function.ClassHierarchyNode; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.*; +import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.nodes.*; @NodeChildren({@NodeChild(value = "object", type = RNode.class), @NodeChild(value = "name", type = RNode.class), @NodeChild(value = "value", type = RNode.class)}) @@ -34,17 +37,39 @@ public abstract class UpdateSlotNode extends RNode { } @SuppressWarnings("unused") - @Specialization(guards = "name == cachedName") + @Specialization(guards = {"!isData(name)", "name == cachedName"}) protected Object updateSlotS4Cached(RAttributable object, String name, Object value, @Cached("name") String cachedName, @Cached("createAttrUpdate(cachedName)") PutAttributeNode attributeUpdate) { attributeUpdate.execute(object.initAttributes(), value); return object; } - @Specialization(contains = "updateSlotS4Cached") + @Specialization(contains = "updateSlotS4Cached", guards = "!isData(name)") protected Object updateSlotS4(RAttributable object, String name, Object value) { assert name == name.intern(); object.setAttr(name, value); return object; } + protected RFunction setDataPartFunction(REnvironment methodsNamespace) { + Object f = methodsNamespace.findFunction("setDataPart"); + return (RFunction) RContext.getRRuntimeASTAccess().forcePromise(f); + } + + private Object setDataPart(RAttributable object, Object value) { + // TODO: any way to cache it or use a mechanism similar to overrides? + REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods"); + RFunction dataPart = setDataPartFunction(methodsNamespace); + return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), object, value, RRuntime.LOGICAL_TRUE); + } + + @Specialization(guards = "isData(name)") + protected Object updateSlotS4Data(RAttributable object, @SuppressWarnings("unused") String name, Object value) { + return setDataPart(object, value); + } + + protected boolean isData(String name) { + assert name == name.intern(); + return name == RRuntime.DOT_DATA; + } + } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java index deeae0c09029ec750993a289b9287b4ad2ccd391..2da71801a5d9e4c807ef023b47c939b0ffd2f03b 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java @@ -131,7 +131,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo public RRootNode duplicateWithNewFrameDescriptor() { FrameDescriptor frameDesc = new FrameDescriptor(); FrameSlotChangeMonitor.initializeFunctionFrameDescriptor(description != null && !description.isEmpty() ? description : "<function>", frameDesc); - return new FunctionDefinitionNode(getSourceSection(), frameDesc, (BodyNode) body.deepCopy(), getFormalArguments(), description, substituteFrame, argPostProcess == null ? null + return new FunctionDefinitionNode(getSourceSection(), frameDesc, (BodyNode) body.unwrap().deepCopy(), getFormalArguments(), description, substituteFrame, argPostProcess == null ? null : (PostProcessArgumentsNode) argPostProcess.deepCopy()); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/DuplicateNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/DuplicateNode.java index 0c236232eb884c7cfba5ce4b9bfd2dadbc44f4ba..3b883e9072c7d1c39abae06a0f5e37b0bbcd4d84 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/DuplicateNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/DuplicateNode.java @@ -51,18 +51,18 @@ public abstract class DuplicateNode extends RBaseNode { @Specialization protected Object duplicate(RS4Object object) { RS4Object newObject = RDataFactory.createS4Object(); - RAttributes newAttributes = newObject.initAttributes(); - for (RAttribute attr : object.getAttributes()) { - newAttributes.put(attr.getName(), attr.getValue()); + if (object.getAttributes() != null) { + RAttributes newAttributes = newObject.initAttributes(); + for (RAttribute attr : object.getAttributes()) { + newAttributes.put(attr.getName(), attr.getValue()); + } } return newObject; } @Specialization protected Object duplicate(RFunction f) { - RFunction newObject = RDataFactory.createFunction(f.getName(), f.getTarget(), f.getRBuiltin(), f.getEnclosingFrame(), f.getFastPath(), f.containsDispatch()); - newObject.initAttributes(f.getAttributes()); - return newObject; + return f.copy(); } // TODO: support more types when required 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 1c67585506a6fbb8b8ee55b0b0a7c3bdce67e28e..60b1220653c7b6136e0c1fa0b08f80567e610033 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 @@ -1522,6 +1522,10 @@ public class RSerialize { break; } + case S4SXP: { + break; + } + /* * FastR scalar, (length 1) "vectors" */ 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 1b200f55b9b0c25a1eeaa6232b36473f5a6a54da..d76cfa027347f061a5046857ad5263e420547cde 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 @@ -105,7 +105,11 @@ public interface RAttributable extends RTypedValue { } default RAttributable setClassAttr(RStringVector classAttr, @SuppressWarnings("unused") boolean convertToInt) { - setAttr(RRuntime.CLASS_ATTR_KEY, classAttr); + if (classAttr == null && getAttributes() != null) { + getAttributes().remove(RRuntime.CLASS_ATTR_KEY); + } else { + setAttr(RRuntime.CLASS_ATTR_KEY, classAttr); + } return this; } 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 b0e0c220351de0c53e8da4d81b5744d7d801b562..04487a6bdbc27bd7429fa309873d769b75c4aa5b 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 @@ -85,7 +85,7 @@ public final class RDataFrame implements RShareable, RAbstractContainer { } @Override - public RVector makeShared() { + public RSharingAttributeStorage makeShared() { return vector.makeShared(); } @@ -109,6 +109,12 @@ public final class RDataFrame implements RShareable, RAbstractContainer { vector.makeSharedPermanent(); } + @Override + public RShareable getNonShared() { + RVector newVector = (RVector) vector.getNonShared(); + return newVector == vector ? this : RDataFactory.createDataFrame(newVector); + } + @Override public RDataFrame copy() { return RDataFactory.createDataFrame(vector.copy()); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java index 8c8cecd7b3dbb661c4042b69e4c3cb0c5c821722..6075944def458fb234b54f4ad1e75f2f53a309f4 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java @@ -180,7 +180,7 @@ public class RExpression implements RShareable, RAbstractContainer { } @Override - public RVector makeShared() { + public RSharingAttributeStorage makeShared() { return data.makeShared(); } @@ -204,6 +204,12 @@ public class RExpression implements RShareable, RAbstractContainer { data.makeSharedPermanent(); } + @Override + public RShareable getNonShared() { + RList newData = (RList) data.getNonShared(); + return newData == data ? this : RDataFactory.createExpression(newData); + } + @Override public RExpression copy() { return RDataFactory.createExpression((RList) data.copy()); 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 1a6f0290daf87d1a2a57122439c1c7f65d4bcd4f..757bbe08758a0ee7dd08ca82b945402391e60974 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 @@ -83,7 +83,7 @@ public final class RFactor implements RShareable, RAbstractContainer { } @Override - public RVector makeShared() { + public RSharingAttributeStorage makeShared() { return vector.makeShared(); } @@ -107,6 +107,12 @@ public final class RFactor implements RShareable, RAbstractContainer { vector.makeSharedPermanent(); } + @Override + public RShareable getNonShared() { + RIntVector newVector = (RIntVector) vector.getNonShared(); + return newVector == vector ? this : RDataFactory.createFactor(newVector, ordered); + } + @Override public RFactor copy() { return RDataFactory.createFactor((RIntVector) vector.copy(), ordered); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java index f3632b1d57f423a2f878bbb363ecf5f7cdc01c29..17108cea26d122649cf52ef4ead713f758c78c74 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java @@ -31,6 +31,7 @@ import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.VirtualEvalFrame; import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute; /** * An instance of {@link RFunction} represents a function defined in R. The properties of a function @@ -44,7 +45,7 @@ import com.oracle.truffle.r.runtime.context.RContext; * {@link #enclosingFrame}. * </ul> */ -public final class RFunction extends RAttributeStorage implements RTypedValue, TruffleObject { +public final class RFunction extends RSharingAttributeStorage implements RTypedValue, TruffleObject { public static final String NO_NAME = new String(""); @@ -126,4 +127,19 @@ public final class RFunction extends RAttributeStorage implements RTypedValue, T public void setFastPath(FastPathFactory fastPath) { this.fastPath = fastPath; } + + @Override + public RShareable copy() { + RFunction newFunction = RDataFactory.createFunction(getName(), getTarget(), getRBuiltin(), getEnclosingFrame(), getFastPath(), containsDispatch()); + if (getAttributes() != null) { + RAttributes newAttributes = newFunction.initAttributes(); + for (RAttribute attr : getAttributes()) { + newAttributes.put(attr.getName(), attr.getValue()); + } + newFunction.initAttributes(newAttributes); + } + return newFunction; + + } + } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java index 3110983e73cc70e6b85a5ee2c03805b65555a13a..2cd03ee404c6aac63257ca362cd8da4c571eebf2 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java @@ -36,11 +36,6 @@ import com.oracle.truffle.r.runtime.nodes.*; * instances. R allows a language element to be treated as a list, hence the support for * {@link RAbstractContainer}, which is implemented via AST walk operations. * - * The representation is inherited from {@link RLanguageRep}. This is a Truffle AST ({@code RNode}), - * although that type is not statically used here due to project circularities. A related - * consequence is the the implementation of the {@link RAbstractContainer} methods are delegated to - * a helper class from a project that can access {@code RNode}. - * * {@link RLanguage} instances are almost completely immutable, <i>except</i> for the ability for * {@code}names} updates which manifests itself as actually transforming the AST. S we do have to * implement the {@link RShareable} interface. @@ -48,11 +43,9 @@ import com.oracle.truffle.r.runtime.nodes.*; * */ @ValueType -public class RLanguage extends RLanguageRep implements RAbstractContainer, RAttributable, RShareable { - - private RAttributes attributes; +public class RLanguage extends RSharingAttributeStorage implements RAbstractContainer, RAttributable, RShareable { - private int gpbits; + private RBaseNode rep; /** * Lazily computed value. @@ -60,31 +53,24 @@ public class RLanguage extends RLanguageRep implements RAbstractContainer, RAttr private int length = -1; RLanguage(RNode rep) { - super(rep); + this.rep = rep; } RLanguage(RNode rep, int length) { - super(rep); + this.rep = rep; this.length = length; } - public RType getRType() { - return RType.Language; + public RBaseNode getRep() { + return rep; } - public RAttributes getAttributes() { - return attributes; + public void setRep(RBaseNode rep) { + this.rep = rep; } - public RAttributes initAttributes() { - if (attributes == null) { - attributes = RAttributes.create(); - } - return attributes; - } - - public final void initAttributes(RAttributes newAttributes) { - attributes = newAttributes; + public RType getRType() { + return RType.Language; } public boolean isComplete() { @@ -124,15 +110,7 @@ public class RLanguage extends RLanguageRep implements RAbstractContainer, RAttr } public RLanguage materializeNonShared() { - if (this.isShared()) { - RLanguage res = this.copy(); - res.markNonTemporary(); - return res; - } - if (this.isTemporary()) { - this.markNonTemporary(); - } - return this; + return (RLanguage) getNonShared(); } public RShareable materializeToShareable() { @@ -183,10 +161,7 @@ public class RLanguage extends RLanguageRep implements RAbstractContainer, RAttr setAttr(RRuntime.ROWNAMES_ATTR_KEY, rowNames); } - public RStringVector getClassHierarchy() { - return RDataFactory.createStringVector(RRuntime.CLASS_LANGUAGE); - } - + @Override public RStringVector getImplicitClass() { return RDataFactory.createStringVector(RRuntime.CLASS_LANGUAGE); } @@ -206,78 +181,9 @@ public class RLanguage extends RLanguageRep implements RAbstractContainer, RAttr return l; } - /* - * RShareable support. Code is cloned directly from RVector. - */ - private boolean shared; - private boolean temporary = true; - private int refCount; - - public void markNonTemporary() { - assert !FastROptions.NewStateTransition.getBooleanValue(); - temporary = false; - } - - public boolean isTemporary() { - if (FastROptions.NewStateTransition.getBooleanValue()) { - return refCount == 0; - } else { - return temporary; - } - } - - public boolean isShared() { - if (FastROptions.NewStateTransition.getBooleanValue()) { - return refCount > 1; - } else { - return shared; - } - } - - public RShareable makeShared() { - assert !FastROptions.NewStateTransition.getBooleanValue(); - if (temporary) { - temporary = false; - } - shared = true; - return this; - } - - public void incRefCount() { - refCount++; - } - - public void decRefCount() { - assert refCount > 0; - refCount--; - } - - @Override - public boolean isSharedPermanent() { - return refCount == SHARED_PERMANENT_VAL; - } - - @Override - public void makeSharedPermanent() { - if (FastROptions.NewStateTransition.getBooleanValue()) { - refCount = SHARED_PERMANENT_VAL; - } else { - // old scheme never reverts states - makeShared(); - } - } - @Override public String toString() { return String.format("RLanguage(rep=%s)", getRep()); } - public int getGPBits() { - return gpbits; - } - - public void setGPBits(int value) { - gpbits = value; - } - } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguageRep.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguageRep.java deleted file mode 100644 index ad923c780644e1d4b0259eef519903c2bfb65bab..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguageRep.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.runtime.data; - -import com.oracle.truffle.r.runtime.nodes.*; - -/** - * Denotes an (unevaluated) element of the R language. - * - * This type is not part of the {@code TypeSystem} but it used as a superclass by {@link RLanguage} - * and {@link RPromise}. - */ -public abstract class RLanguageRep { - - private RBaseNode rep; - - public RLanguageRep(RBaseNode rep) { - this.rep = rep; - } - - public RBaseNode getRep() { - return rep; - } - - public void setRep(RBaseNode rep) { - this.rep = rep; - } -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java index b440411fb8ce778c888e4bb47d05a423d2691920..8dd712e267ce30feb03e298fd255d663d7bc2e92 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java @@ -38,7 +38,7 @@ import com.oracle.truffle.r.runtime.nodes.*; * which is used for manual method dispatch. */ @ValueType -public class RPromise extends RLanguageRep implements RTypedValue { +public class RPromise implements RTypedValue { /** * Different to GNU R, FastR has no additional binding information (a "origin" where the binding @@ -79,6 +79,8 @@ public class RPromise extends RLanguageRep implements RTypedValue { public static final String CLOSURE_WRAPPER_NAME = new String("<promise>"); + private RBaseNode rep; + /** * @see PromiseType */ @@ -112,7 +114,7 @@ public class RPromise extends RLanguageRep implements RTypedValue { * This creates a new tuple (expr, env, closure, value=null), which may later be evaluated. */ RPromise(PromiseType type, OptType optType, MaterializedFrame execFrame, Closure closure) { - super(closure.getExpr()); + this.rep = closure.getExpr(); assert type != PromiseType.ARG_DEFAULT || execFrame != null; this.type = type; this.optType = optType; @@ -124,7 +126,7 @@ public class RPromise extends RLanguageRep implements RTypedValue { * This creates a new tuple (expr, null, null, value), which is already evaluated. */ RPromise(PromiseType type, OptType optType, RBaseNode expr, Object value) { - super(expr); + this.rep = expr; assert value != null; this.type = type; this.optType = optType; @@ -139,7 +141,7 @@ public class RPromise extends RLanguageRep implements RTypedValue { * called via {@link VarargPromise#VarargPromise(PromiseType, RPromise, Closure)} only! */ private RPromise(PromiseType type, OptType optType, RBaseNode expr) { - super(expr); + this.rep = expr; this.type = type; this.optType = optType; // Not needed as already evaluated: @@ -147,6 +149,14 @@ public class RPromise extends RLanguageRep implements RTypedValue { this.closure = null; } + public RBaseNode getRep() { + return rep; + } + + public void setRep(RBaseNode rep) { + this.rep = rep; + } + public RType getRType() { return RType.Promise; } @@ -192,15 +202,6 @@ public class RPromise extends RLanguageRep implements RTypedValue { return frame == execFrame; } - /** - * @return The representation of expression (a RNode). May contain <code>null</code> if no expr - * is provided! - */ - @Override - public final RBaseNode getRep() { - return super.getRep(); - } - /** * @return {@link #closure} */ @@ -485,4 +486,9 @@ public class RPromise extends RLanguageRep implements RTypedValue { throw RInternalError.shouldNotReachHere(); } + @Override + public boolean isS4() { + return false; + } + } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalar.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalar.java index c33f21afb8a19358ac403a80edfe6f58426938b8..869c48e8c691f3911feedb2d02ebea78e466d635 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalar.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalar.java @@ -38,4 +38,9 @@ public abstract class RScalar implements RTypedValue { throw RInternalError.shouldNotReachHere(); } + @Override + public boolean isS4() { + return false; + } + } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java index e112e6b5047510aadb810d236d4708edf6ae17a7..3c407bdb435d835b9a481f567bc9ab00bcc9c7bf 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java @@ -199,4 +199,9 @@ public abstract class RSequence implements RAbstractVector { throw RInternalError.shouldNotReachHere(); } + @Override + public boolean isS4() { + return false; + } + } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RShareable.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RShareable.java index b929568d6a3bdc488a8f9e35c28c09d678786c75..9d92ad3f944fc4520ac7e127240921c883515aa5 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RShareable.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RShareable.java @@ -52,4 +52,6 @@ public interface RShareable { void makeSharedPermanent(); + RShareable getNonShared(); + } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSharingAttributeStorage.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSharingAttributeStorage.java new file mode 100644 index 0000000000000000000000000000000000000000..1a29ac41f8b5709a370775b4e129ad2a8daf94ed --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSharingAttributeStorage.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data; + +import com.oracle.truffle.r.runtime.*; + +/** + * An adaptor class for the several R types that are both attributable and shareable. + */ +public abstract class RSharingAttributeStorage extends RAttributeStorage implements RShareable { + + private int refCount; + + private static final int TEMPORARY = 0x1; + private static final int SHARED = 0x2; + + protected RSharingAttributeStorage() { + if (!FastROptions.NewStateTransition.getBooleanValue()) { + refCount = TEMPORARY; + } + } + + @Override + public final void markNonTemporary() { + assert !FastROptions.NewStateTransition.getBooleanValue(); + refCount &= ~TEMPORARY; + } + + @Override + public final boolean isTemporary() { + if (FastROptions.NewStateTransition.getBooleanValue()) { + return refCount == 0; + } else { + return (refCount & TEMPORARY) != 0; + } + } + + @Override + public final boolean isShared() { + if (FastROptions.NewStateTransition.getBooleanValue()) { + return refCount > 1; + } else { + return (refCount & SHARED) != 0; + } + } + + @Override + public final RSharingAttributeStorage makeShared() { + assert !FastROptions.NewStateTransition.getBooleanValue(); + refCount = SHARED; + return this; + } + + @Override + public final void incRefCount() { + refCount++; + } + + @Override + public final void decRefCount() { + assert refCount > 0; + refCount--; + } + + @Override + public boolean isSharedPermanent() { + return refCount == SHARED_PERMANENT_VAL; + } + + @Override + public void makeSharedPermanent() { + if (FastROptions.NewStateTransition.getBooleanValue()) { + refCount = SHARED_PERMANENT_VAL; + } else { + // old scheme never reverts states + makeShared(); + } + } + + public RShareable getNonShared() { + if (this.isShared()) { + RShareable res = this.copy(); + if (FastROptions.NewStateTransition.getBooleanValue()) { + assert res.isTemporary(); + res.incRefCount(); + } else { + res.markNonTemporary(); + } + return res; + } + if (this.isTemporary()) { + // this is needed for primitive value coercion - they need to be marked as + // non-temp, otherwise the following code will not work: + // x<-1; attributes(x) <- list(my = 1); y<-x; attributes(y)<-list(his = 2); x + if (FastROptions.NewStateTransition.getBooleanValue()) { + this.incRefCount(); + } else { + this.markNonTemporary(); + } + } + return 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 1f3cfb2aa5faab424d6b48e913ba0c53c6b393c2..74e5f21fa6e931fbc04a19a9d6dbf60b2e4bf27f 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 @@ -49,7 +49,7 @@ import com.oracle.truffle.r.runtime.nodes.*; * - non-shared => shared * </pre> */ -public abstract class RVector extends RAttributeStorage implements RShareable, RAbstractVector, RFFIAccess { +public abstract class RVector extends RSharingAttributeStorage implements RShareable, RAbstractVector, RFFIAccess { private static final RStringVector implicitClassHeaderArray = RDataFactory.createStringVector(new String[]{RType.Array.getName()}, true); private static final RStringVector implicitClassHeaderMatrix = RDataFactory.createStringVector(new String[]{RType.Matrix.getName()}, true); @@ -60,19 +60,12 @@ public abstract class RVector extends RAttributeStorage implements RShareable, R private RList dimNames; // cache rownames for data frames as they are accessed at every data frame access private Object rowNames; - private int refCount; - - private static final int TEMPORARY = 0x1; - private static final int SHARED = 0x2; protected RVector(boolean complete, int length, int[] dimensions, RStringVector names) { this.complete = complete; this.dimensions = dimensions; this.names = names; this.rowNames = RNull.instance; - if (!FastROptions.NewStateTransition.getBooleanValue()) { - refCount = TEMPORARY; - } if (names != null) { // since this constructor is for internal use only, the assertion shouldn't fail assert names.getLength() == length : "size mismatch: " + names.getLength() + " vs. " + length; @@ -423,63 +416,6 @@ public abstract class RVector extends RAttributeStorage implements RShareable, R return complete; } - @Override - public final void markNonTemporary() { - assert !FastROptions.NewStateTransition.getBooleanValue(); - refCount &= ~TEMPORARY; - } - - @Override - public final boolean isTemporary() { - if (FastROptions.NewStateTransition.getBooleanValue()) { - return refCount == 0; - } else { - return (refCount & TEMPORARY) != 0; - } - } - - @Override - public final boolean isShared() { - if (FastROptions.NewStateTransition.getBooleanValue()) { - return refCount > 1; - } else { - return (refCount & SHARED) != 0; - } - } - - @Override - public final RVector makeShared() { - assert !FastROptions.NewStateTransition.getBooleanValue(); - refCount = SHARED; - return this; - } - - @Override - public final void incRefCount() { - refCount++; - } - - @Override - public final void decRefCount() { - assert refCount > 0; - refCount--; - } - - @Override - public boolean isSharedPermanent() { - return refCount == SHARED_PERMANENT_VAL; - } - - @Override - public void makeSharedPermanent() { - if (FastROptions.NewStateTransition.getBooleanValue()) { - refCount = SHARED_PERMANENT_VAL; - } else { - // old scheme never reverts states - makeShared(); - } - } - public final boolean hasDimensions() { return dimensions != null; } @@ -855,28 +791,8 @@ public abstract class RVector extends RAttributeStorage implements RShareable, R } @Override - public final RVector materializeNonShared() { - if (this.isShared()) { - RVector res = this.copy(); - if (FastROptions.NewStateTransition.getBooleanValue()) { - assert res.isTemporary(); - res.incRefCount(); - } else { - res.markNonTemporary(); - } - return res; - } - if (this.isTemporary()) { - // this is needed for primitive values coerced to vector - they need to be marked as - // non-temp, otherwise the following code will not work: - // x<-1; attributes(x) <- list(my = 1); y<-x; attributes(y)<-list(his = 2); x - if (FastROptions.NewStateTransition.getBooleanValue()) { - this.incRefCount(); - } else { - this.markNonTemporary(); - } - } - return this; + public RVector materializeNonShared() { + return (RVector) getNonShared(); } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java index 6fef32a799a3c20b1573ee874847b2bc00220679..a0baa2b12d372960943cdde06c6e5e16066d5616 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java @@ -184,4 +184,9 @@ public abstract class RToVectorClosure implements RAbstractVector { vector.setGPBits(value); } + @Override + public boolean isS4() { + return false; + } + } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java index 5fac432ac6303c5bc066df6bb0154826237ea84e..2d2654f8efdca8112f7126a7a198f58b4be00c7a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java @@ -46,7 +46,7 @@ public enum SEXPTYPE { EXTPTRSXP(22, RExternalPtr.class), /* external pointer */ WEAKREFSXP(23), /* weak reference */ RAWSXP(24, new Class<?>[]{RRawVector.class, RRaw.class}), /* raw bytes */ - S4SXP(25), /* S4 non-vector */ + S4SXP(25, RS4Object.class), /* S4 non-vector */ NEWSXP(30), /* fresh node created in new page */ FREESXP(31), /* node released by GC */ 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 f6880d4a82f9d94c583dd9311592551b1e298d19..524dfb633e07580e16dcf8788e0712d139485df9 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 @@ -39,6 +39,26 @@ Error: unexpected '}' in "{ asS4(NULL); isS4(NULL }" #{ x<-42; y<-asS4(x); isS4(y) } [1] TRUE +##com.oracle.truffle.r.test.S4.TestS4.testMethods +#{ gen<-function(object) 0; setGeneric("gen"); gen } +standardGeneric for "gen" defined from package ".GlobalEnv" + +function (object) +standardGeneric("gen") +<environment: 0x100835ce8> +Methods may be defined for arguments: object +Use showMethods("gen") for currently available ones. + +##com.oracle.truffle.r.test.S4.TestS4.testMethods +#{ setGeneric("gen", function(object) standardGeneric("gen")); gen } +standardGeneric for "gen" defined from package ".GlobalEnv" + +function (object) +standardGeneric("gen") +<environment: 0x101efac38> +Methods may be defined for arguments: object +Use showMethods("gen") for currently available ones. + ##com.oracle.truffle.r.test.S4.TestS4.testSlotAccess #{ `@`(getClass("ClassUnionRepresentation"), "virtual") } [1] FALSE @@ -11774,6 +11794,10 @@ attr(,"package") #{ x <- new.env(); class(x); class(x)<-c("abc", "xyz"); class(x); class(x)<-NULL; class(x) } [1] "environment" +##com.oracle.truffle.r.test.builtins.TestBuiltin_classassign.testUpdateClass +#{ x<-function() 42; class(x)<-"foo"; class(x)<-NULL; x } +function() 42 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_classassign.testUpdateClass #{ x=1;class(x)<-"character"; x} [1] "1" @@ -56577,6 +56601,12 @@ $dimnames[[2]] +##com.oracle.truffle.r.test.library.base.TestSimpleAttributes.testDefinition +#{ x<-function() 42; attr(x, "foo")<-"foo"; y<-x; attr(y, "foo")<-NULL; x } +function() 42 +attr(,"foo") +[1] "foo" + ##com.oracle.truffle.r.test.library.base.TestSimpleAttributes.testOtherPropagation #{ x <- 1:2; attr(x, "hi") <- 2 ; x == x } [1] TRUE TRUE diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestS4.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestS4.java index 841483337f558eeba372a8617c6242cd8830c321..05b3c4b9de774b1b77f0995b610a6f7783549203 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestS4.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestS4.java @@ -82,4 +82,11 @@ public class TestS4 extends TestBase { // output slightly different from GNU R even though we use R's "show" method to print it assertEval(Ignored.OutputFormatting, "{ setClass(\"foo\", representation(j=\"numeric\")); getClass(\"foo\") }"); } + + @Test + public void testMethods() { + // output slightly different from GNU R even though we use R's "show" method to print it + assertEval(Ignored.OutputFormatting, "{ setGeneric(\"gen\", function(object) standardGeneric(\"gen\")); gen }"); + assertEval(Ignored.OutputFormatting, "{ gen<-function(object) 0; setGeneric(\"gen\"); gen }"); + } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_classassign.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_classassign.java index e9eb18ac71eb5eeb10f2a049c41862fad4cdfa71..7f4704b531f74bece273094a3e0b6be5a0640421 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_classassign.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_classassign.java @@ -184,5 +184,7 @@ public class TestBuiltin_classassign extends TestBase { assertEval(Output.ContainsError, "{x<-c(1,2,3,4); class(x)<-\"array\"; class(x)<-\"matrix\";}"); assertEval(Output.ContainsError, "{x<-1;attr(x,\"class\")<-c(1,2,3);}"); + + assertEval("{ x<-function() 42; class(x)<-\"foo\"; class(x)<-NULL; x }"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleAttributes.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleAttributes.java index 1d7ded250087787d1b3e9d65032273a81940cbec..3f8f17e223d37780285308bf27ec19ad62d8e6ff 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleAttributes.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleAttributes.java @@ -42,6 +42,8 @@ public class TestSimpleAttributes extends TestBase { assertEval("{ x<-1:4; attributes(x)<-list(dim=c(2,2), dimnames=list(c(1,2), c(3,4))); attributes(x) }"); assertEval("{ attributes(NULL) }"); + + assertEval("{ x<-function() 42; attr(x, \"foo\")<-\"foo\"; y<-x; attr(y, \"foo\")<-NULL; x }"); } @Test