-
-
Notifications
You must be signed in to change notification settings - Fork 925
Commit
…hing their companion class to them.
- 9.4.12.0
- 9.4.11.0
- 9.4.10.0
- 9.4.9.0
- 9.4.8.0
- 9.4.7.0
- 9.4.6.0
- 9.4.5.0
- 9.4.4.0
- 9.4.3.0
- 9.4.2.0
- 9.4.1.0
- 9.4.0.0
- 9.3.15.0
- 9.3.14.0
- 9.3.13.0
- 9.3.12.0
- 9.3.11.0
- 9.3.10.0
- 9.3.9.0
- 9.3.8.0
- 9.3.7.0
- 9.3.6.0
- 9.3.5.0
- 9.3.4.0
- 9.3.3.0
- 9.3.2.0
- 9.3.1.0
- 9.3.0.0
- 9.2.21.0
- 9.2.20.1
- 9.2.20.0
- 9.2.19.0
- 9.2.18.0
- 9.2.17.0
- 9.2.16.0
- 9.2.15.0
- 9.2.14.0
- 9.2.13.0
- 9.2.12.0
- 9.2.11.1
- 9.2.11.0
- 9.2.10.0
- 9.2.9.0
- 9.2.8.0
- 9.2.7.0
- 9.2.6.0
- 9.2.5.0
- 9.2.4.1
- 9.2.4.0
- 9.2.3.0
- 9.2.2.0
- 9.2.1.0
- 9.2.0.0
- 9.1.17.0
- 9.1.16.0
- 9.1.15.0
- 9.1.14.0
- 9.1.13.0
- 9.1.12.0
- 9.1.11.0
- 9.1.10.0
- 9.1.9.0
- 9.1.8.0
- 9.1.7.0
- 9.1.6.0
- 9.1.5.0
- 9.1.4.0
- 9.1.3.0
- 9.1.2.0
- 9.1.1.0
- 9.1.0.0
- 9.0.5.0
- 9.0.4.0
- 9.0.3.0
- 9.0.1.0
- 9.0.0.0
- 9.0.0.0.rc2
- 9.0.0.0.rc1
- 9.0.0.0.pre2
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -243,6 +243,14 @@ public static Object lookupClassVariable(RubyModule module, String name) { | |
} | ||
} | ||
|
||
if (module instanceof RubyClass) { | ||
RubyClass klass = (RubyClass) module; | ||
|
||
if (klass.isSingleton()) { | ||
return lookupClassVariable(((RubyClass) module).getAttached(), name); | ||
} | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
eregon
Member
|
||
} | ||
|
||
// Nothing found | ||
|
||
return null; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -104,8 +104,13 @@ public RubyClass getSingletonClass(Node currentNode) { | |
|
||
final RubyClass logicalClass = metaClass; | ||
|
||
metaClass = RubyClass.createSingletonClassOfObject(getContext(), logicalClass, | ||
String.format("#<Class:#<%s:0x%x>>", logicalClass.getName(), getObjectID())); | ||
if (this instanceof RubyModule) { | ||
metaClass = RubyClass.createSingletonClassOfObject(getContext(), logicalClass, (RubyModule) this, | ||
String.format("#<Class:#<%s:0x%x>>", logicalClass.getName(), getObjectID())); | ||
} else { | ||
metaClass = RubyClass.createSingletonClassOfObject(getContext(), logicalClass, logicalClass, | ||
This comment has been minimized.
Sorry, something went wrong.
eregon
Member
|
||
String.format("#<Class:#<%s:0x%x>>", logicalClass.getName(), getObjectID())); | ||
} | ||
|
||
if (DebugOperations.verySlowIsFrozen(this)) { | ||
DebugOperations.verySlowFreeze(metaClass); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,7 @@ public class RubyClass extends RubyModule { | |
|
||
private final boolean isSingleton; | ||
private final Set<RubyClass> subClasses = Collections.newSetFromMap(new WeakHashMap<RubyClass, Boolean>()); | ||
@CompilationFinal private RubyModule attached; | ||
This comment has been minimized.
Sorry, something went wrong.
eregon
Member
|
||
|
||
/** | ||
* This constructor supports initialization and solves boot-order problems and should not | ||
|
@@ -48,10 +49,10 @@ public RubyClass(RubyContext context, RubyModule lexicalParent, RubyClass superc | |
ensureSingletonConsistency(); | ||
} | ||
|
||
protected static RubyClass createSingletonClassOfObject(RubyContext context, RubyClass superclass, String name) { | ||
protected static RubyClass createSingletonClassOfObject(RubyContext context, RubyClass superclass, RubyModule attached, String name) { | ||
// We also need to create the singleton class of a singleton class for proper lookup and consistency. | ||
// See rb_singleton_class() documentation in MRI. | ||
return new RubyClass(context, superclass.getLogicalClass(), null, superclass, name, true).ensureSingletonConsistency(); | ||
return new RubyClass(context, superclass.getLogicalClass(), null, superclass, name, true, attached).ensureSingletonConsistency(); | ||
} | ||
|
||
protected RubyClass(RubyContext context, RubyClass classClass, RubyModule lexicalParent, RubyClass superclass, String name, boolean isSingleton) { | ||
|
@@ -64,6 +65,14 @@ protected RubyClass(RubyContext context, RubyClass classClass, RubyModule lexica | |
} | ||
} | ||
|
||
protected RubyClass(RubyContext context, RubyClass classClass, RubyModule lexicalParent, RubyClass superclass, String name, boolean isSingleton, RubyModule attached) { | ||
this(context, classClass, lexicalParent, superclass, name, isSingleton); | ||
|
||
assert isSingleton == true; | ||
|
||
this.attached = attached; | ||
} | ||
|
||
public void initialize(RubyClass superclass) { | ||
unsafeSetSuperclass(superclass); | ||
ensureSingletonConsistency(); | ||
|
@@ -124,7 +133,7 @@ private RubyClass createOneSingletonClass() { | |
} | ||
|
||
metaClass = new RubyClass(getContext(), | ||
getLogicalClass(), null, singletonSuperclass, String.format("#<Class:%s>", getName()), true); | ||
getLogicalClass(), null, singletonSuperclass, String.format("#<Class:%s>", getName()), true, this); | ||
|
||
return metaClass; | ||
} | ||
|
@@ -137,6 +146,10 @@ public boolean isSingleton() { | |
return isSingleton; | ||
} | ||
|
||
public RubyModule getAttached() { | ||
return attached; | ||
} | ||
|
||
public RubyClass getSuperClass() { | ||
CompilerAsserts.neverPartOfCompilation(); | ||
|
||
|
8 comments
on commit 0e29b6b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eregon Please review this when you get some time. I'm not happy with all the instanceof checks. I think some of them can be converted to specialization guards, particularly in SingletonClassNode
, but doing it this way allowed me to hit every case at once. If this is the wrong approach, please feel free to revert. But it appears to be working for class << self
in both classes and modules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid the instanceof checks we could just implement it for all objects like MRI does. So make attached
an Object and always assign it when creating the singleton class.
About constructors, I am very much in favor of not creating new ones, but rather having a single one that does most of the job. It is much harder to follow the flow with many constructors. What we really need is constructors with a "name", which can achieved with factory methods on the class, and enforced by making the constructor private. Adding the extra parameter to all callers is also almost trivial with refactoring so keeping the old constructor has no real benefit. Keeping the assert would be good though in the form of assert !isSingleton || attached != null
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems there is not yet a compelling use case to have attached
for non-Module, so let's keep the instanceof checks (MRI uses it for detailed errors).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can change the constructor stuff easily enough. I intentionally kept the commit a bit "incomplete" to illustrate the general idea. I didn't want to change a bunch of files just to find out this was the wrong approach. I probably should have just done this on a branch though... I'll go through and clean up later today.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, thanks for the thorough review!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, doing it in a branch or PR would be quite nice to be able to edit the commit :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eregon Yeah, it was late and I wasn't thinking. Want me to revert the commit and we can clean this up on a different branch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you prefer, I can look up the resulting files as well. But I do find value in having commits doing just the right thing too, so feel free to do as you see fit.
Recursion should be used as last resort in general.
In particular, here MRI does not look in the hierarchy of the sclass, just in the sclass itself.