Skip to content

Commit 394532f

Browse files
andrykonchineregon
authored andcommitted
[GR-45621] Add Class#attached_object method
PullRequest: truffleruby/4126
2 parents 740a6e1 + b41ec83 commit 394532f

File tree

7 files changed

+29
-10
lines changed

7 files changed

+29
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Compatibility:
3434
* Implement `rb_check_funcall()` (@eregon).
3535
* Implement `MatchData#{byteoffset,deconstruct,deconstruct_keys}` from Ruby 3.2 (#3039, @rwstauner).
3636
* Add `Integer#ceildiv` method (#3039, @simonlevasseur, @nirvdrum).
37+
* Implement `Class#attached_object` method (#3039, @andrykonchin).
3738

3839
Performance:
3940

spec/ruby/core/class/attached_object_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@
1919
it "raises TypeError if the class is not a singleton class" do
2020
a = Class.new
2121

22-
-> { a.attached_object }.should raise_error(TypeError)
22+
-> { a.attached_object }.should raise_error(TypeError, /is not a singleton class/)
2323
end
2424

2525
it "raises TypeError for special singleton classes" do
26-
-> { nil.singleton_class.attached_object }.should raise_error(TypeError)
27-
-> { true.singleton_class.attached_object }.should raise_error(TypeError)
28-
-> { false.singleton_class.attached_object }.should raise_error(TypeError)
26+
-> { nil.singleton_class.attached_object }.should raise_error(TypeError, /`NilClass' is not a singleton class/)
27+
-> { true.singleton_class.attached_object }.should raise_error(TypeError, /`TrueClass' is not a singleton class/)
28+
-> { false.singleton_class.attached_object }.should raise_error(TypeError, /`FalseClass' is not a singleton class/)
2929
end
3030
end
3131
end

spec/tags/core/class/attached_object_tags.txt

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/main/java/org/truffleruby/core/exception/CoreExceptions.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,12 @@ public RubyException typeErrorCantCreateInstanceOfSingletonClass(Node currentNod
548548
return typeError("can't create instance of singleton class", currentNode, null);
549549
}
550550

551+
@TruffleBoundary
552+
public RubyException typeErrorNotASingletonClass(Node currentNode, RubyClass rubyClass) {
553+
String className = rubyClass.fields.getName();
554+
return typeError(StringUtils.format("`%s' is not a singleton class", className), currentNode, null);
555+
}
556+
551557
@TruffleBoundary
552558
public RubyException superclassMismatch(String name, Node currentNode) {
553559
return typeError("superclass mismatch for class " + name, currentNode);

src/main/java/org/truffleruby/core/klass/ClassNodes.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,22 @@ RubyClass newSingletonInstance(RubyClass rubyClass) {
276276
}
277277
}
278278

279+
@CoreMethod(names = "attached_object")
280+
public abstract static class AttachedObjectNode extends CoreMethodArrayArgumentsNode {
281+
282+
@Specialization(guards = "rubyClass.isSingleton")
283+
Object attachedObject(RubyClass rubyClass) {
284+
return rubyClass.attached;
285+
}
286+
287+
@Specialization(guards = "!rubyClass.isSingleton")
288+
Object attachedObjectOfNonSingletonClass(RubyClass rubyClass) {
289+
throw new RaiseException(
290+
getContext(),
291+
getContext().getCoreExceptions().typeErrorNotASingletonClass(this, rubyClass));
292+
}
293+
}
294+
279295
// Worth always splitting to have monomorphic #__allocate__ and #initialize,
280296
// Worth always inlining as the field accesses and initializations are optimized when the allocation is visible,
281297
// and a non-inlined call to #__allocate__ would allocate the arguments Object[] which is about the same number of

src/main/java/org/truffleruby/core/klass/RubyClass.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public final class RubyClass extends RubyModule implements ObjectGraphNode {
3737
public final boolean isSingleton;
3838
/** If this is an object's metaclass, then nonSingletonClass is the logical class of the object. */
3939
public final RubyClass nonSingletonClass;
40+
/** Ruby object which this class is a metaclass/singleton class of */
4041
public final RubyDynamicObject attached;
4142
/* a RubyClass or nil for BasicObject */
4243
public final Object superclass;
@@ -57,6 +58,7 @@ public RubyClass(
5758
Object superclass) {
5859
super(classClass, language.classShape, language, sourceSection, lexicalParent, givenBaseName);
5960
assert !isSingleton || givenBaseName == null;
61+
assert isSingleton == (attached != null);
6062
this.isSingleton = isSingleton;
6163
this.attached = attached;
6264
this.nonSingletonClass = computeNonSingletonClass(isSingleton, superclass);
@@ -83,7 +85,6 @@ public RubyClass(
8385
fields.afterConstructed();
8486
}
8587

86-
8788
/** Special constructor to build the 'Class' RubyClass itself. */
8889
RubyClass(RubyLanguage language, Shape classShape) {
8990
super(language, classShape, "constructor only for the class Class");

test/mri/excludes/TestClass.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,3 @@
1515
exclude :test_subclass_gc, "NoMethodError: undefined method `subclasses' for #<Class:0x25fd48>"
1616
exclude :test_subclass_gc_stress, "NoMethodError: undefined method `subclasses' for #<Class:0x11c93f8>"
1717
exclude :test_subclasses, "NoMethodError: undefined method `subclasses' for #<Class:0x11c9b48>"
18-
exclude :test_attached_object, "NoMethodError: undefined method `attached_object' for #<Class:#<#<Class:0x197b18>:0x197b28>>"

0 commit comments

Comments
 (0)