Skip to content

Commit 7486467

Browse files
committed
[GR-19220] Implement Module#const_source_location (#2212)
PullRequest: truffleruby/2365
2 parents 772fa62 + 778b89b commit 7486467

File tree

3 files changed

+58
-30
lines changed

3 files changed

+58
-30
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Compatibility:
4444
* Support the `inherit` parameter for `Module#{private, protected, public}_method_defined?`.
4545
* Implement `Thread.pending_interrupt?` and `Thread#pending_interrupt?` (#2219).
4646
* Implement `rb_lastline_set` (#2170).
47+
* Implemented `Module#const_source_location` (#2212, @tomstuart and @wildmaples).
4748

4849
Performance:
4950

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,2 @@
1-
fails:Module#const_source_location return empty path if constant defined in C code
2-
fails:Module#const_source_location accepts a String or Symbol name
3-
fails:Module#const_source_location returns nil if no constant is defined in the search path
4-
fails:Module#const_source_location raises a NameError if the name contains non-alphabetic characters except '_'
51
fails:Module#const_source_location calls #to_str to convert the given name to a String
6-
fails:Module#const_source_location raises a TypeError if conversion to a String by calling #to_str fails
7-
fails:Module#const_source_location does not search the singleton class of a Class or Module
8-
fails:Module#const_source_location does not search the containing scope
9-
fails:Module#const_source_location returns nil if the constant is defined in the receiver's superclass and the inherit flag is false
10-
fails:Module#const_source_location searches into the receiver superclasses if the inherit flag is true
11-
fails:Module#const_source_location returns nil when the receiver is a Module, the constant is defined at toplevel and the inherit flag is false
12-
fails:Module#const_source_location returns nil when the receiver is a Class, the constant is defined at toplevel and the inherit flag is false
13-
fails:Module#const_source_location accepts a toplevel scope qualifier
14-
fails:Module#const_source_location accepts a scoped constant name
15-
fails:Module#const_source_location does search private constants path
16-
fails:Module#const_source_location with dynamically assigned constants searches a path in the immediate class or module first
17-
fails:Module#const_source_location with dynamically assigned constants searches a path in a module included in the immediate class before the superclass
18-
fails:Module#const_source_location with dynamically assigned constants searches a path in the superclass before a module included in the superclass
19-
fails:Module#const_source_location with dynamically assigned constants searches a path in a module included in the superclass
20-
fails:Module#const_source_location with dynamically assigned constants searches a path in the superclass chain
21-
fails:Module#const_source_location with dynamically assigned constants returns path to a toplevel constant when the receiver is a Class
22-
fails:Module#const_source_location with dynamically assigned constants returns path to a toplevel constant when the receiver is a Module
23-
fails:Module#const_source_location with dynamically assigned constants returns path to the updated value of a constant
24-
fails:Module#const_source_location with statically assigned constants searches location path the immediate class or module first
25-
fails:Module#const_source_location with statically assigned constants searches location path a module included in the immediate class before the superclass
26-
fails:Module#const_source_location with statically assigned constants searches location path the superclass before a module included in the superclass
27-
fails:Module#const_source_location with statically assigned constants searches location path a module included in the superclass
28-
fails:Module#const_source_location with statically assigned constants searches location path the superclass chain
29-
fails:Module#const_source_location with statically assigned constants returns location path a toplevel constant when the receiver is a Class
30-
fails:Module#const_source_location with statically assigned constants returns location path a toplevel constant when the receiver is a Module
312
fails:Module#const_source_location autoload returns the autoload location while not resolved
32-
fails:Module#const_source_location autoload returns where the constant was resolved when resolved

src/main/java/org/truffleruby/core/module/ModuleNodes.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
import org.truffleruby.language.arguments.ReadPreArgumentNode;
7878
import org.truffleruby.language.arguments.ReadSelfNode;
7979
import org.truffleruby.language.arguments.RubyArguments;
80+
import org.truffleruby.language.backtrace.BacktraceFormatter;
8081
import org.truffleruby.language.constants.GetConstantNode;
8182
import org.truffleruby.language.constants.LookupConstantInterface;
8283
import org.truffleruby.language.constants.LookupConstantNode;
@@ -1072,6 +1073,62 @@ protected Object constMissing(RubyModule module, String name) {
10721073

10731074
}
10741075

1076+
@CoreMethod(names = "const_source_location", required = 1, optional = 1)
1077+
@NodeChild(value = "module", type = RubyNode.class)
1078+
@NodeChild(value = "name", type = RubyNode.class)
1079+
@NodeChild(value = "inherit", type = RubyNode.class)
1080+
public abstract static class ConstSourceLocationNode extends CoreMethodNode {
1081+
1082+
@Child private MakeStringNode makeStringNode = MakeStringNode.create();
1083+
1084+
@CreateCast("name")
1085+
protected RubyNode coerceToStringOrSymbol(RubyNode name) {
1086+
return ToStringOrSymbolNodeGen.create(name);
1087+
}
1088+
1089+
@CreateCast("inherit")
1090+
protected RubyNode coerceToBoolean(RubyNode inherit) {
1091+
return BooleanCastWithDefaultNodeGen.create(true, inherit);
1092+
}
1093+
1094+
@Specialization(guards = { "strings.isRubyString(name)" })
1095+
@TruffleBoundary
1096+
protected Object constSourceLocation(RubyModule module, Object name, boolean inherit,
1097+
@CachedLibrary(limit = "2") RubyStringLibrary strings) {
1098+
final ConstantLookupResult lookupResult = ModuleOperations
1099+
.lookupScopedConstant(getContext(), module, strings.getJavaString(name), inherit, this, true);
1100+
1101+
return getLocation(lookupResult);
1102+
}
1103+
1104+
@Specialization
1105+
@TruffleBoundary
1106+
protected Object constSourceLocation(RubyModule module, RubySymbol name, boolean inherit) {
1107+
final ConstantLookupResult lookupResult = ModuleOperations
1108+
.lookupConstantWithInherit(getContext(), module, name.getString(), inherit, this, true);
1109+
1110+
return getLocation(lookupResult);
1111+
}
1112+
1113+
private Object getLocation(ConstantLookupResult lookupResult) {
1114+
if (!lookupResult.isFound()) {
1115+
return nil;
1116+
}
1117+
1118+
final SourceSection sourceSection = lookupResult.getConstant().getSourceSection();
1119+
if (!BacktraceFormatter.isAvailable(sourceSection)) {
1120+
return createEmptyArray();
1121+
} else {
1122+
final RubyString file = makeStringNode.executeMake(
1123+
getContext().getSourcePath(sourceSection.getSource()),
1124+
UTF8Encoding.INSTANCE,
1125+
CodeRange.CR_UNKNOWN);
1126+
return createArray(new Object[]{ file, sourceSection.getStartLine() });
1127+
}
1128+
}
1129+
1130+
}
1131+
10751132
@CoreMethod(names = "const_set", required = 2)
10761133
@NodeChild(value = "module", type = RubyNode.class)
10771134
@NodeChild(value = "name", type = RubyNode.class)

0 commit comments

Comments
 (0)