Skip to content

Commit 05e27ec

Browse files
committed
Dont lose lexical scope refinements for super call
1 parent 4cfe9f6 commit 05e27ec

File tree

3 files changed

+78
-9
lines changed

3 files changed

+78
-9
lines changed

spec/ruby/core/module/refine_spec.rb

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,7 @@ def bar
817817
end
818818
end
819819

820-
it "does't have access to refinement from included module" do
820+
it "does't have access to active refinements for C from included module" do
821821
refined_class = ModuleSpecs.build_refined_class
822822

823823
a = Module.new do
@@ -836,9 +836,40 @@ def bar
836836
end
837837
end
838838

839+
Module.new do
840+
using refinement
841+
-> {
842+
refined_class.new.foo
843+
}.should raise_error(NameError) { |e| e.name.should == :bar }
844+
end
845+
end
846+
847+
it "does't have access to other active refinements from included module" do
848+
refined_class = ModuleSpecs.build_refined_class
849+
850+
refinement_integer = Module.new do
851+
refine Integer do
852+
def bar
853+
"bar is not seen from A methods"
854+
end
855+
end
856+
end
857+
858+
a = Module.new do
859+
def foo
860+
super + 1.bar
861+
end
862+
end
863+
864+
refinement = Module.new do
865+
refine refined_class do
866+
include a
867+
end
868+
end
839869

840870
Module.new do
841871
using refinement
872+
using refinement_integer
842873
-> {
843874
refined_class.new.foo
844875
}.should raise_error(NameError) { |e| e.name.should == :bar }
@@ -922,6 +953,40 @@ def foo
922953

923954
result.should == [:B, :A, :LAST, :C]
924955
end
956+
957+
it "looks in the lexical scope refinements before other active refinements" do
958+
refined_class = ModuleSpecs.build_refined_class(for_super: true)
959+
960+
refinement_local = Module.new do
961+
refine refined_class do
962+
def foo
963+
[:LOCAL] + super
964+
end
965+
end
966+
end
967+
968+
a = Module.new do
969+
using refinement_local
970+
971+
def foo
972+
[:A] + super
973+
end
974+
end
975+
976+
refinement = Module.new do
977+
refine refined_class do
978+
include a
979+
end
980+
end
981+
982+
result = nil
983+
Module.new do
984+
using refinement
985+
result = refined_class.new.foo
986+
end
987+
988+
result.should == [:A, :LOCAL, :C]
989+
end
925990
end
926991

927992
it 'and alias aliases a method within a refinement module, but not outside it' do

src/main/java/org/truffleruby/language/methods/UsingNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,14 @@ private Map<DynamicObject, DynamicObject[]> usingModule(DeclarationContext decla
6363
.getFields(ancestor)
6464
.getRefinements();
6565
for (Map.Entry<DynamicObject, DynamicObject> entry : refinements.entrySet()) {
66-
usingRefinement(entry.getKey(), entry.getValue(), newRefinements);
66+
applyRefinements(entry.getKey(), entry.getValue(), newRefinements);
6767
}
6868
}
6969

7070
return newRefinements;
7171
}
7272

73-
private void usingRefinement(DynamicObject refinedModule, DynamicObject refinementModule,
73+
public static void applyRefinements(DynamicObject refinedModule, DynamicObject refinementModule,
7474
Map<DynamicObject, DynamicObject[]> newRefinements) {
7575
final DynamicObject[] refinements = newRefinements.get(refinedModule);
7676
if (refinements == null) {

src/main/java/org/truffleruby/language/supercall/LookupSuperMethodNode.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.truffleruby.language.arguments.RubyArguments;
1717
import org.truffleruby.language.methods.DeclarationContext;
1818
import org.truffleruby.language.methods.InternalMethod;
19+
import org.truffleruby.language.methods.UsingNode;
1920
import org.truffleruby.language.objects.MetaClassNode;
2021

2122
import com.oracle.truffle.api.CompilerDirectives;
@@ -95,18 +96,21 @@ protected int getCacheLimit() {
9596
private DeclarationContext getDeclarationContext(InternalMethod currentMethod,
9697
DynamicObject selfMetaClass) {
9798
final DeclarationContext context = currentMethod.getDeclarationContext();
98-
final DeclarationContext activeRefinements = currentMethod.getActiveRefinements();
99+
final DeclarationContext callerContext = currentMethod.getActiveRefinements();
99100

100-
if (activeRefinements != null) {
101+
if (callerContext != null) {
101102
// super from the refined method has access to the parent's active refinements for the selfMetaClass
102-
final DynamicObject[] classRefinements = activeRefinements.getRefinementsFor(selfMetaClass);
103+
final DynamicObject[] activeRefinements = callerContext.getRefinementsFor(selfMetaClass);
103104

104-
if (classRefinements == null) {
105+
if (activeRefinements == null) {
105106
return context;
106107
} else {
107-
// add to the context active refinements for the selfMetaClass
108108
final Map<DynamicObject, DynamicObject[]> newRefinements = new HashMap<>(context.getRefinements());
109-
newRefinements.put(selfMetaClass, classRefinements);
109+
110+
// add class refinements in reverse order to keep the original positions
111+
for (int i = activeRefinements.length - 1; i >= 0; i--) {
112+
UsingNode.applyRefinements(selfMetaClass, activeRefinements[i], newRefinements);
113+
}
110114

111115
return context.withRefinements(newRefinements);
112116
}

0 commit comments

Comments
 (0)