[opengoal] make none a child of object (#3001)

Previously, `object` and `none` were both top-level types. This made
decompilation rather messy as they have no LCA and resulted in a lot of
variables coming out as type `none` which is very very wrong and
additionally there were plenty of casts to `object`. This changes it so
`none` becomes a child of `object` (it is still represented by
`NullType` which remains unusable in compilation).

This change makes `object` the sole top-level type, and the type that
can represent *any* GOAL object. I believe this matches the original
GOAL built-in type structure. A function that has a return type of
`object` can now return an integer or a `none` at the same time.
However, keep in mind that the return value of `(none)` is still
undefined, just as before. This also makes a cast to `object`
meaningless in 90% of the situations it showed up in (as every single
thing is already an `object`) and the decompiler will no longer emit
them. Casts to `none` are also reduced. Yay!

Additionally, state handlers also don't get the final `(none)` printed
out anymore. The return type of a state handler is completely
meaningless outside the event handler (which is return type `object`
anyway) so there are no limitations on what the last form needs to be. I
did this instead of making them return `object` to trick the decompiler
into not trying to output a variable to be used as a return value
(internally, in the decompiler they still have return type `none`, but
they have `object` elsewhere).

Fixes #1703 
Fixes #830 
Fixes #928
This commit is contained in:
ManDude
2023-09-22 10:54:49 +01:00
committed by GitHub
parent 697b07abd5
commit fe491c2b5e
964 changed files with 24949 additions and 39444 deletions
+11 -46
View File
@@ -655,34 +655,23 @@ namespace {
TP_Type lca_for_var_types(const TP_Type& existing,
const TP_Type& add,
const DecompilerTypeSystem& dts,
bool event_handler_hack) {
const DecompilerTypeSystem& dts) {
bool changed;
auto normal = dts.tp_lca(existing, add, &changed);
if (!event_handler_hack || normal.typespec().base_type() != "none") {
return normal;
}
if (existing.typespec().base_type() == "none") {
return add;
} else if (add.typespec().base_type() == "none") {
return existing;
} else {
return normal;
}
return normal;
}
void update_var_info(VariableNames::VarInfo* info,
Register reg,
const TypeState& ts,
int var_id,
const DecompilerTypeSystem& dts,
bool event_handler_hack) {
const DecompilerTypeSystem& dts) {
auto& type = ts.get(reg);
if (info->initialized) {
ASSERT(info->reg_id.id == var_id);
ASSERT(info->reg_id.reg == reg);
info->type = lca_for_var_types(info->type, type, dts, event_handler_hack);
info->type = lca_for_var_types(info->type, type, dts);
} else {
info->reg_id.id = var_id;
@@ -695,10 +684,9 @@ void update_var_info(VariableNames::VarInfo* info,
bool merge_infos(VariableNames::VarInfo* info1,
VariableNames::VarInfo* info2,
const DecompilerTypeSystem& dts,
bool event_handler_hack) {
const DecompilerTypeSystem& dts) {
if (info1->initialized && info2->initialized) {
auto new_type = lca_for_var_types(info1->type, info2->type, dts, event_handler_hack);
auto new_type = lca_for_var_types(info1->type, info2->type, dts);
info1->type = new_type;
info2->type = new_type;
@@ -710,13 +698,12 @@ bool merge_infos(VariableNames::VarInfo* info1,
void merge_infos(
std::unordered_map<Register, std::vector<VariableNames::VarInfo>, Register::hash>& info1,
std::unordered_map<Register, std::vector<VariableNames::VarInfo>, Register::hash>& info2,
const DecompilerTypeSystem& dts,
bool event_handler_hack) {
const DecompilerTypeSystem& dts) {
for (auto& [reg, infos] : info1) {
auto other = info2.find(reg);
if (other != info2.end()) {
for (size_t i = 0; i < std::min(other->second.size(), infos.size()); i++) {
merge_infos(&infos.at(i), &other->second.at(i), dts, event_handler_hack);
merge_infos(&infos.at(i), &other->second.at(i), dts);
}
}
}
@@ -730,28 +717,6 @@ void merge_infos(
* the none variables
*/
void SSA::make_vars(const Function& function, const DecompilerTypeSystem& dts) {
bool event_handler_hack = false;
if (function.ir2.env.version == GameVersion::Jak2) {
event_handler_hack = function.guessed_name.is_event_handler() ||
function.guessed_name.to_string() == "target-generic-event-handler" ||
function.guessed_name.to_string() == "target-standard-event-handler" ||
function.guessed_name.to_string() == "target-board-handler" ||
function.guessed_name.to_string() == "(method 74 pegasus)" ||
function.guessed_name.to_string() == "(method 74 crimson-guard-level)" ||
function.guessed_name.to_string() == "widow-handler" ||
function.guessed_name.to_string() == "(method 74 hal)" ||
function.guessed_name.to_string() == "water-anim-event-handler" ||
function.guessed_name.to_string() == "(method 74 civilian)" ||
function.guessed_name.to_string() == "(method 74 crimson-guard)" ||
function.guessed_name.to_string() == "metalkor-handler";
}
if (function.ir2.env.version == GameVersion::Jak1) {
event_handler_hack = function.guessed_name.is_event_handler() ||
function.guessed_name.to_string() == "target-generic-event-handler";
}
for (int block_id = 0; block_id < int(blocks.size()); block_id++) {
const auto& block = blocks.at(block_id);
const TypeState* init_types = &function.ir2.env.get_types_at_block_entry(block_id);
@@ -766,13 +731,13 @@ void SSA::make_vars(const Function& function, const DecompilerTypeSystem& dts) {
if (instr.dst.has_value()) {
auto var_id = map.var_id(*instr.dst);
auto* info = &program_write_vars[instr.dst->reg()].at(var_id);
update_var_info(info, instr.dst->reg(), *end_types, var_id, dts, event_handler_hack);
update_var_info(info, instr.dst->reg(), *end_types, var_id, dts);
}
for (auto& src : instr.src) {
auto var_id = map.var_id(src);
auto* info = &program_read_vars[src.reg()].at(var_id);
update_var_info(info, src.reg(), *init_types, var_id, dts, event_handler_hack);
update_var_info(info, src.reg(), *init_types, var_id, dts);
}
init_types = end_types;
@@ -793,7 +758,7 @@ void SSA::make_vars(const Function& function, const DecompilerTypeSystem& dts) {
}
}
merge_infos(program_write_vars, program_read_vars, dts, event_handler_hack);
merge_infos(program_write_vars, program_read_vars, dts);
// copy types from input argument coloring moves:
for (auto& instr : blocks.at(0).ins) {