Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/GlobalState.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ class GlobalState final {
bool isSCIPRuby = true;

// --- begin scip-ruby specific state
// Mapping describing which field references in a class are still
// marked as "unresolved" after name resolution is complete.
UnorderedMap<core::ClassOrModuleRef, UnorderedSet<core::NameRef>> unresolvedFields;
// --- end scip-ruby specific state

Expand Down
9 changes: 9 additions & 0 deletions resolver/resolver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4188,6 +4188,15 @@ class CollectUnresolvedFieldsWalk final {
gs.unresolvedFields.insert(make_move_iterator(threadResult.unresolvedFields.begin()),
make_move_iterator(threadResult.unresolvedFields.end()));
}
// NOTE(varun): This walker is meant to be invoked after name resolution is finished.
// As such, one might expect that the unresolved fields across classes stay the same
// across runs, as all the single-threaded merging which requires cross-file data
// is complete. However, that's not the case. 😕
//
// In particular, when testing on the shopify-ruby-codebase, printing the
// printing the number of unresolved fields for each class gave varying results
// (e.g. in one run, a class would have 85 unresolved fields, in another run,
// it would have 87 unresolved fields).
}

fast_sort(trees, [](const auto &lhs, const auto &rhs) -> bool { return lhs.file < rhs.file; });
Expand Down
18 changes: 0 additions & 18 deletions scip_indexer/SCIPFieldResolve.cc
Original file line number Diff line number Diff line change
Expand Up @@ -78,24 +78,6 @@ core::ClassOrModuleRef FieldResolver::findUnresolvedFieldInInheritanceChain(cons
}
start = FieldResolver::normalizeParentForClassVar(gs, start, fieldText);

if (gs.unresolvedFields.find(start) == gs.unresolvedFields.end() ||
!gs.unresolvedFields.find(start)->second.contains(field)) {
// Triggered by code patterns like:
// # top-level
// def MyClass.method
// # blah
// end
// which is not supported by Sorbet.
LOG_DEBUG(gs, debugLoc,
fmt::format("couldn't find field {} in class {};\n"
"are you using a code pattern like def MyClass.method which is unsupported by Sorbet?",
field.exists() ? field.toString(gs) : "<non-existent>",
start.exists() ? start.showFullName(gs) : "<non-existent>"));
// As a best-effort guess, assume that the definition is
// in this class but we somehow missed it.
return start;
}

auto best = start;
auto cur = start;
while (cur.exists()) {
Expand Down