Skip to content

Commit 53e7253

Browse files
committed
Always use the line offset when reporting the line of a Source
* Fixes #3065
1 parent 2b4657a commit 53e7253

19 files changed

+81
-86
lines changed

spec/ruby/core/binding/source_location_spec.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,9 @@
66
b = BindingSpecs::LocationMethod::TEST_BINDING
77
b.source_location.should == [BindingSpecs::LocationMethod::FILE_PATH, 4]
88
end
9+
10+
it "works for eval with a given line" do
11+
b = eval('binding', nil, "foo", 100)
12+
b.source_location.should == ["foo", 100]
13+
end
914
end

spec/ruby/core/method/source_location_spec.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ def f
104104
end
105105
end
106106

107+
it "works for eval with a given line" do
108+
c = Class.new do
109+
eval('def self.m; end', nil, "foo", 100)
110+
end
111+
c.method(:m).source_location.should == ["foo", 100]
112+
end
113+
107114
describe "for a Method generated by respond_to_missing?" do
108115
it "returns nil" do
109116
m = MethodSpecs::Methods.new

spec/ruby/core/module/const_source_location_spec.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,13 @@
210210
ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE]
211211
end
212212

213+
it "works for eval with a given line" do
214+
c = Class.new do
215+
eval('self::C = 1', nil, "foo", 100)
216+
end
217+
c.const_source_location(:C).should == ["foo", 100]
218+
end
219+
213220
context 'autoload' do
214221
before :all do
215222
ConstantSpecs.autoload :CSL_CONST1, "#{__dir__}/notexisting.rb"

spec/ruby/core/proc/source_location_spec.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,9 @@
8383

8484
proc.source_location.should == nil
8585
end
86+
87+
it "works for eval with a given line" do
88+
proc = eval('-> {}', nil, "foo", 100)
89+
proc.source_location.should == ["foo", 100]
90+
end
8691
end

spec/ruby/core/unboundmethod/source_location_spec.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,11 @@
4949
method.source_location[0].should =~ /#{__FILE__}/
5050
method.source_location[1].should == line
5151
end
52+
53+
it "works for eval with a given line" do
54+
c = Class.new do
55+
eval('def m; end', nil, "foo", 100)
56+
end
57+
c.instance_method(:m).source_location.should == ["foo", 100]
58+
end
5259
end

src/main/java/org/truffleruby/RubyLanguage.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.truffleruby.core.array.RubyArray;
4545
import org.truffleruby.core.basicobject.RubyBasicObject;
4646
import org.truffleruby.core.binding.RubyBinding;
47+
import org.truffleruby.core.encoding.Encodings;
4748
import org.truffleruby.core.encoding.RubyEncoding;
4849
import org.truffleruby.core.encoding.RubyEncodingConverter;
4950
import org.truffleruby.core.exception.RubyException;
@@ -99,12 +100,13 @@
99100
import org.truffleruby.interop.RubyInnerContext;
100101
import org.truffleruby.interop.RubySourceLocation;
101102
import org.truffleruby.language.LexicalScope;
102-
import org.truffleruby.language.Nil;
103+
import org.truffleruby.language.RubyBaseNode;
103104
import org.truffleruby.language.RubyDynamicObject;
104105
import org.truffleruby.language.RubyEvalInteractiveRootNode;
105106
import org.truffleruby.language.RubyInlineParsingRequestNode;
106107
import org.truffleruby.language.RubyParsingRequestNode;
107108
import org.truffleruby.language.arguments.KeywordArgumentsDescriptorManager;
109+
import org.truffleruby.language.backtrace.BacktraceFormatter;
108110
import org.truffleruby.language.objects.RubyObjectType;
109111
import org.truffleruby.language.objects.classvariables.ClassVariableStorage;
110112
import org.truffleruby.language.threadlocal.SpecialVariableStorage;
@@ -134,6 +136,8 @@
134136
import com.oracle.truffle.api.utilities.CyclicAssumption;
135137
import org.truffleruby.stdlib.digest.RubyDigest;
136138

139+
import static org.truffleruby.language.RubyBaseNode.nil;
140+
137141
@TruffleLanguage.Registration(
138142
name = "Ruby",
139143
website = "https://www.graalvm.org/ruby/",
@@ -185,7 +189,7 @@ public final class RubyLanguage extends TruffleLanguage<RubyContext> {
185189
/** This is a truly empty frame descriptor and should only by dummy root nodes which require no variables. Any other
186190
* root nodes should should use
187191
* {@link TranslatorEnvironment#newFrameDescriptorBuilder(org.truffleruby.parser.ParentFrameDescriptor, boolean)}. */
188-
public static final FrameDescriptor EMPTY_FRAME_DESCRIPTOR = new FrameDescriptor(Nil.INSTANCE);
192+
public static final FrameDescriptor EMPTY_FRAME_DESCRIPTOR = new FrameDescriptor(nil);
189193

190194
private RubyThread getOrCreateForeignThread(RubyContext context, Thread thread) {
191195
RubyThread foreignThread = rubyThreadInitMap.remove(thread);
@@ -842,6 +846,7 @@ public static String getPath(Source source) {
842846
/** {@link RubyLanguage#getPath(Source)} but also handles core library sources. Ideally this method would be static
843847
* but for now the core load path is an option and it also depends on the current working directory. Once we have
844848
* Source metadata in Truffle we could use that to identify core library sources without needing the language. */
849+
@TruffleBoundary
845850
public String getSourcePath(Source source) {
846851
final String path = getPath(source);
847852
if (path.startsWith(coreLoadPath)) {
@@ -906,6 +911,18 @@ public static String filenameLine(SourceSection section) {
906911
}
907912
}
908913

914+
public Object rubySourceLocation(RubyContext context, SourceSection section,
915+
TruffleString.FromJavaStringNode fromJavaStringNode,
916+
RubyBaseNode node) {
917+
if (!BacktraceFormatter.isAvailable(section)) {
918+
return nil;
919+
} else {
920+
var file = node.createString(fromJavaStringNode, getSourcePath(section.getSource()), Encodings.UTF_8);
921+
Object[] objects = new Object[]{ file, RubySource.getStartLineAdjusted(context, section) };
922+
return node.createArray(objects);
923+
}
924+
}
925+
909926
public int getGlobalVariableIndex(String name) {
910927
return globalVariablesMap.lookup(name);
911928
}

src/main/java/org/truffleruby/cext/CExtNodes.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@
143143
import com.oracle.truffle.api.profiles.BranchProfile;
144144
import com.oracle.truffle.api.profiles.ConditionProfile;
145145
import com.oracle.truffle.api.source.SourceSection;
146+
import org.truffleruby.parser.RubySource;
146147

147148
@CoreModule("Truffle::CExt")
148149
public class CExtNodes {
@@ -1180,7 +1181,7 @@ public abstract static class SourceLineNode extends CoreMethodArrayArgumentsNode
11801181
@Specialization
11811182
protected int sourceLine() {
11821183
final SourceSection sourceSection = SourceFileNode.getTopUserSourceSection("rb_sourceline");
1183-
return sourceSection.getStartLine();
1184+
return RubySource.getStartLineAdjusted(getContext(), sourceSection);
11841185
}
11851186

11861187
}

src/main/java/org/truffleruby/core/binding/BindingNodes.java

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@
3333
import org.truffleruby.core.array.ArrayHelpers;
3434
import org.truffleruby.core.array.RubyArray;
3535
import org.truffleruby.core.cast.NameToJavaStringNode;
36-
import org.truffleruby.core.encoding.Encodings;
3736
import org.truffleruby.core.klass.RubyClass;
38-
import org.truffleruby.core.string.RubyString;
3937
import org.truffleruby.language.RubyBaseNode;
4038
import org.truffleruby.language.RubyBaseNodeWithExecute;
4139
import org.truffleruby.language.RubyNode;
@@ -533,24 +531,14 @@ protected Object receiver(RubyBinding binding) {
533531
}
534532
}
535533

536-
// NOTE: Introduced in Ruby 2.6, but already useful for Binding#eval
537534
@CoreMethod(names = "source_location")
538535
public abstract static class SourceLocationNode extends CoreMethodArrayArgumentsNode {
539536

540-
@TruffleBoundary
541537
@Specialization
542538
protected Object sourceLocation(RubyBinding binding,
543539
@Cached TruffleString.FromJavaStringNode fromJavaStringNode) {
544-
final SourceSection sourceSection = binding.sourceSection;
545-
546-
if (sourceSection == null) {
547-
return nil;
548-
} else {
549-
final RubyString file = createString(fromJavaStringNode,
550-
getLanguage().getSourcePath(sourceSection.getSource()),
551-
Encodings.UTF_8);
552-
return createArray(new Object[]{ file, sourceSection.getStartLine() });
553-
}
540+
var sourceSection = binding.sourceSection;
541+
return getLanguage().rubySourceLocation(getContext(), sourceSection, fromJavaStringNode, this);
554542
}
555543
}
556544

src/main/java/org/truffleruby/core/method/MethodNodes.java

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import org.truffleruby.core.Hashing;
2121
import org.truffleruby.core.array.RubyArray;
2222
import org.truffleruby.core.basicobject.BasicObjectNodes.ReferenceEqualNode;
23-
import org.truffleruby.core.encoding.Encodings;
2423
import org.truffleruby.core.inlined.AlwaysInlinedMethodNode;
2524
import org.truffleruby.core.klass.RubyClass;
2625
import org.truffleruby.core.module.MethodLookupResult;
@@ -30,7 +29,6 @@
3029
import org.truffleruby.core.proc.ProcOperations;
3130
import org.truffleruby.core.proc.ProcType;
3231
import org.truffleruby.core.proc.RubyProc;
33-
import org.truffleruby.core.string.RubyString;
3432
import org.truffleruby.core.symbol.RubySymbol;
3533
import org.truffleruby.language.RubyContextSourceNode;
3634
import org.truffleruby.language.RubyLambdaRootNode;
@@ -56,7 +54,6 @@
5654
import com.oracle.truffle.api.dsl.Specialization;
5755
import com.oracle.truffle.api.frame.MaterializedFrame;
5856
import com.oracle.truffle.api.frame.VirtualFrame;
59-
import com.oracle.truffle.api.source.SourceSection;
6057

6158
@CoreModule(value = "Method", isClass = true)
6259
public abstract class MethodNodes {
@@ -229,30 +226,17 @@ public abstract static class ReceiverNode extends CoreMethodArrayArgumentsNode {
229226
protected Object receiver(RubyMethod method) {
230227
return method.receiver;
231228
}
232-
233229
}
234230

235231
@CoreMethod(names = "source_location")
236232
public abstract static class SourceLocationNode extends CoreMethodArrayArgumentsNode {
237233

238-
@Child private TruffleString.FromJavaStringNode fromJavaStringNode = TruffleString.FromJavaStringNode.create();
239-
240-
@TruffleBoundary
241234
@Specialization
242-
protected Object sourceLocation(RubyMethod method) {
243-
SourceSection sourceSection = method.method.getSharedMethodInfo().getSourceSection();
244-
245-
if (!sourceSection.isAvailable()) {
246-
return nil;
247-
} else {
248-
RubyString file = createString(
249-
fromJavaStringNode,
250-
getLanguage().getSourcePath(sourceSection.getSource()),
251-
Encodings.UTF_8);
252-
return createArray(new Object[]{ file, sourceSection.getStartLine() });
253-
}
235+
protected Object sourceLocation(RubyMethod method,
236+
@Cached TruffleString.FromJavaStringNode fromJavaStringNode) {
237+
var sourceSection = method.method.getSharedMethodInfo().getSourceSection();
238+
return getLanguage().rubySourceLocation(getContext(), sourceSection, fromJavaStringNode, this);
254239
}
255-
256240
}
257241

258242
@CoreMethod(names = "super_method")

src/main/java/org/truffleruby/core/method/UnboundMethodNodes.java

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,10 @@
2121
import org.truffleruby.core.Hashing;
2222
import org.truffleruby.core.array.RubyArray;
2323
import org.truffleruby.core.cast.ToSymbolNode;
24-
import org.truffleruby.core.encoding.Encodings;
2524
import org.truffleruby.core.klass.RubyClass;
2625
import org.truffleruby.core.module.MethodLookupResult;
2726
import org.truffleruby.core.module.ModuleOperations;
2827
import org.truffleruby.core.module.RubyModule;
29-
import org.truffleruby.core.string.RubyString;
3028
import org.truffleruby.core.symbol.RubySymbol;
3129
import org.truffleruby.language.RubyGuards;
3230
import org.truffleruby.annotations.Visibility;
@@ -45,7 +43,6 @@
4543
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
4644
import com.oracle.truffle.api.dsl.Cached;
4745
import com.oracle.truffle.api.dsl.Specialization;
48-
import com.oracle.truffle.api.source.SourceSection;
4946

5047
@CoreModule(value = "UnboundMethod", isClass = true)
5148
public abstract class UnboundMethodNodes {
@@ -210,27 +207,12 @@ protected RubyArray parameters(RubyUnboundMethod method) {
210207
@CoreMethod(names = "source_location")
211208
public abstract static class SourceLocationNode extends CoreMethodArrayArgumentsNode {
212209

213-
@Child private TruffleString.FromJavaStringNode fromJavaStringNode = TruffleString.FromJavaStringNode.create();
214-
215-
@TruffleBoundary
216210
@Specialization
217-
protected Object sourceLocation(RubyUnboundMethod unboundMethod) {
218-
SourceSection sourceSection = unboundMethod.method
219-
.getSharedMethodInfo()
220-
.getSourceSection();
221-
222-
if (!sourceSection.isAvailable()) {
223-
return nil;
224-
} else {
225-
RubyString file = createString(
226-
fromJavaStringNode,
227-
getLanguage().getSourcePath(sourceSection.getSource()),
228-
Encodings.UTF_8);
229-
Object[] objects = new Object[]{ file, sourceSection.getStartLine() };
230-
return createArray(objects);
231-
}
211+
protected Object sourceLocation(RubyUnboundMethod unboundMethod,
212+
@Cached TruffleString.FromJavaStringNode fromJavaStringNode) {
213+
var sourceSection = unboundMethod.method.getSharedMethodInfo().getSourceSection();
214+
return getLanguage().rubySourceLocation(getContext(), sourceSection, fromJavaStringNode, this);
232215
}
233-
234216
}
235217

236218
@CoreMethod(names = "super_method")

0 commit comments

Comments
 (0)