Skip to content

Commit 81d9de2

Browse files
feat: Add support for fields, attr_* and funcs in method calls (#21)
This patch rewrites the handling for aliases to largely consistently handle classes etc., instead of having one-off hacks. (TBF, I didn't fully understand how aliases worked earlier.) Thanks to this, constants also seem to mostly work now. Additionally, adding support for attr_* forms required that we support emitting references for functions in method invocations properly. So I fixed that too. The earlier implementation of trying recursive lookup seems very silly in hindsight. 🤦🏽 However thanks to this change, we also get support for occurrences from the stdlib for "free."
1 parent 9605fd8 commit 81d9de2

File tree

11 files changed

+655
-194
lines changed

11 files changed

+655
-194
lines changed

cfg/builder/builder.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ class CFGContext {
4747
BasicBlock *breakScope;
4848
BasicBlock *rescueScope;
4949
std::shared_ptr<core::SendAndBlockLink> link;
50-
UnorderedMap<core::SymbolRef, LocalRef> &aliases;
51-
UnorderedMap<core::NameRef, LocalRef> &discoveredUndeclaredFields;
50+
UnorderedMap<core::SymbolRef, LocalOccurrence> &aliases;
51+
UnorderedMap<core::NameRef, LocalOccurrence> &discoveredUndeclaredFields;
5252

5353
uint32_t &temporaryCounter;
5454

@@ -64,8 +64,8 @@ class CFGContext {
6464
private:
6565
friend std::unique_ptr<CFG> CFGBuilder::buildFor(core::Context ctx, ast::MethodDef &md);
6666
CFGContext(core::Context ctx, CFG &inWhat, LocalOccurrence target, int loops, BasicBlock *nextScope,
67-
BasicBlock *breakScope, BasicBlock *rescueScope, UnorderedMap<core::SymbolRef, LocalRef> &aliases,
68-
UnorderedMap<core::NameRef, LocalRef> &discoveredUndeclaredFields, uint32_t &temporaryCounter)
67+
BasicBlock *breakScope, BasicBlock *rescueScope, UnorderedMap<core::SymbolRef, LocalOccurrence> &aliases,
68+
UnorderedMap<core::NameRef, LocalOccurrence> &discoveredUndeclaredFields, uint32_t &temporaryCounter)
6969
: ctx(ctx), inWhat(inWhat), target(target), loops(loops), isInsideRubyBlock(false), breakIsJump(false),
7070
nextScope(nextScope), breakScope(breakScope), rescueScope(rescueScope), aliases(aliases),
7171
discoveredUndeclaredFields(discoveredUndeclaredFields), temporaryCounter(temporaryCounter){};

cfg/builder/builder_entry.cc

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ unique_ptr<CFG> CFGBuilder::buildFor(core::Context ctx, ast::MethodDef &md) {
1515
res->loc = md.loc;
1616
res->symbol = md.symbol.data(ctx)->dealiasMethod(ctx);
1717
uint32_t temporaryCounter = 1;
18-
UnorderedMap<core::SymbolRef, LocalRef> aliases;
19-
UnorderedMap<core::NameRef, LocalRef> discoveredUndeclaredFields;
18+
UnorderedMap<core::SymbolRef, LocalOccurrence> aliases;
19+
UnorderedMap<core::NameRef, LocalOccurrence> discoveredUndeclaredFields;
2020
CFGContext cctx(ctx, *res.get(), LocalOccurrence::synthetic(LocalRef::noVariable()), 0, nullptr, nullptr, nullptr,
2121
aliases, discoveredUndeclaredFields, temporaryCounter);
2222

@@ -107,11 +107,10 @@ unique_ptr<CFG> CFGBuilder::buildFor(core::Context ctx, ast::MethodDef &md) {
107107
vector<Binding> aliasesPrefix;
108108
for (auto kv : aliases) {
109109
core::SymbolRef global = kv.first;
110-
LocalRef local = kv.second;
111-
aliasesPrefix.emplace_back(LocalOccurrence::synthetic(local), core::LocOffsets::none(),
112-
make_insn<Alias>(global));
110+
LocalOccurrence local = kv.second;
111+
aliasesPrefix.emplace_back(LocalOccurrence::synthetic(local.variable), local.loc, make_insn<Alias>(global));
113112
if (global.isFieldOrStaticField()) {
114-
res->minLoops[local.id()] = CFG::MIN_LOOP_FIELD;
113+
res->minLoops[local.variable.id()] = CFG::MIN_LOOP_FIELD;
115114
} else {
116115
// We used to have special handling here for "MIN_LOOP_GLOBAL" but it was meaningless,
117116
// because it only happened for type members, and we already prohibit re-assigning type
@@ -122,9 +121,9 @@ unique_ptr<CFG> CFGBuilder::buildFor(core::Context ctx, ast::MethodDef &md) {
122121
}
123122
}
124123
for (auto kv : discoveredUndeclaredFields) {
125-
aliasesPrefix.emplace_back(LocalOccurrence::synthetic(kv.second), core::LocOffsets::none(),
124+
aliasesPrefix.emplace_back(LocalOccurrence::synthetic(kv.second.variable), kv.second.loc,
126125
make_insn<Alias>(core::Symbols::Magic_undeclaredFieldStub(), kv.first));
127-
res->minLoops[kv.second.id()] = CFG::MIN_LOOP_FIELD;
126+
res->minLoops[kv.second.variable.id()] = CFG::MIN_LOOP_FIELD;
128127
}
129128
histogramInc("cfgbuilder.aliases", aliasesPrefix.size());
130129
auto basicBlockCreated = res->basicBlocks.size();

cfg/builder/builder_walk.cc

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,20 @@ void CFGBuilder::unconditionalJump(BasicBlock *from, BasicBlock *to, CFG &inWhat
4343

4444
namespace {
4545

46-
LocalRef global2Local(CFGContext cctx, core::SymbolRef what) {
46+
LocalRef global2Local(CFGContext cctx, core::SymbolRef what, core::LocOffsets loc) {
4747
if (what == core::Symbols::StubModule()) {
4848
// We don't need all stub module assignments to alias to the same temporary.
4949
// (The fact that there's a StubModule at all means an error was already reported elsewhere)
5050
return cctx.newTemporary(what.name(cctx.ctx));
5151
}
5252

5353
// Note: this will add an empty local to aliases if 'what' is not there
54-
LocalRef &alias = cctx.aliases[what];
55-
if (!alias.exists()) {
56-
alias = cctx.newTemporary(what.name(cctx.ctx));
54+
auto &alias = cctx.aliases[what];
55+
if (!alias.variable.exists()) {
56+
alias.loc = loc;
57+
alias.variable = cctx.newTemporary(what.name(cctx.ctx));
5758
}
58-
return alias;
59+
return alias.variable;
5960
}
6061

6162
LocalRef unresolvedIdent2Local(CFGContext cctx, const ast::UnresolvedIdent &id) {
@@ -91,12 +92,12 @@ LocalRef unresolvedIdent2Local(CFGContext cctx, const ast::UnresolvedIdent &id)
9192
}
9293
}
9394
auto ret = cctx.newTemporary(id.name);
94-
cctx.discoveredUndeclaredFields[id.name] = ret;
95+
cctx.discoveredUndeclaredFields[id.name] = {ret, id.loc};
9596
return ret;
9697
}
97-
return fnd->second;
98+
return fnd->second.variable;
9899
} else {
99-
return global2Local(cctx, sym);
100+
return global2Local(cctx, sym, id.loc);
100101
}
101102
}
102103

@@ -329,7 +330,7 @@ BasicBlock *CFGBuilder::walk(CFGContext cctx, ast::ExpressionPtr &what, BasicBlo
329330
[&](ast::Assign &a) {
330331
LocalRef lhs;
331332
if (auto lhsIdent = ast::cast_tree<ast::ConstantLit>(a.lhs)) {
332-
lhs = global2Local(cctx, lhsIdent->symbol);
333+
lhs = global2Local(cctx, lhsIdent->symbol, a.loc);
333334
} else if (auto lhsLocal = ast::cast_tree<ast::Local>(a.lhs)) {
334335
lhs = cctx.inWhat.enterLocal(lhsLocal->localVariable);
335336
} else if (auto ident = ast::cast_tree<ast::UnresolvedIdent>(a.lhs)) {

0 commit comments

Comments
 (0)