[goalc] speed up jak3 compilation (#3454)

I noticed that jak 3's compilation was spending a lot of time accessing
the `unordered_map`s we use to store constants and symbol types.

 
I repurposed the `EnvironmentMap` originally made for GOOS for this. It
turns out that we were copying the entire constant map whenever we
encountered a `deftype`, and fixed that too.

This speeds up jak3 compiles from ~16 to 11 seconds for me.
This commit is contained in:
water111 2024-04-06 16:01:17 -04:00 committed by GitHub
parent 376194a3e7
commit cc8801a27b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 192 additions and 218 deletions

View File

@ -571,104 +571,6 @@ Object Interpreter::eval(Object obj, const std::shared_ptr<EnvironmentObject>& e
}
}
EnvironmentMap::EnvironmentMap() {
clear();
}
void EnvironmentMap::clear() {
m_entries.clear();
m_power_of_two_size = 3; // 2 ^ 3 = 8
m_entries.resize(8);
m_used_entries = 0;
m_next_resize = (m_entries.size() * kMaxUsed);
m_mask = 0b111;
}
Object* EnvironmentMap::lookup(InternedSymbolPtr str) {
if (m_entries.size() < 10) {
for (auto& e : m_entries) {
if (e.key == str.name_ptr) {
return &e.value;
}
}
return nullptr;
}
u32 hash = crc32((const u8*)&str.name_ptr, sizeof(const char*));
// probe
for (u32 i = 0; i < m_entries.size(); i++) {
u32 slot_addr = (hash + i) & m_mask;
auto& slot = m_entries[slot_addr];
if (!slot.key) {
return nullptr;
} else {
if (slot.key != str.name_ptr) {
continue; // bad hash
}
return &slot.value;
}
}
// should be impossible to reach.
ASSERT_NOT_REACHED();
}
void EnvironmentMap::set(InternedSymbolPtr ptr, const Object& obj) {
u32 hash = crc32((const u8*)&ptr.name_ptr, sizeof(const char*));
// probe
for (u32 i = 0; i < m_entries.size(); i++) {
u32 slot_addr = (hash + i) & m_mask;
auto& slot = m_entries[slot_addr];
if (!slot.key) {
// not found, insert!
slot.key = ptr.name_ptr;
slot.value = obj;
m_used_entries++;
if (m_used_entries >= m_next_resize) {
resize();
}
return;
} else {
if (slot.key == ptr.name_ptr) {
slot.value = obj;
return;
}
}
}
// should be impossible to reach.
ASSERT_NOT_REACHED();
}
void EnvironmentMap::resize() {
m_power_of_two_size++;
m_mask = (1U << m_power_of_two_size) - 1;
std::vector<Entry> new_entries(m_entries.size() * 2);
for (const auto& old_entry : m_entries) {
if (old_entry.key) {
bool done = false;
u32 hash = crc32((const u8*)&old_entry.key, sizeof(const char*));
for (u32 i = 0; i < new_entries.size(); i++) {
u32 slot_addr = (hash + i) & m_mask;
auto& slot = new_entries[slot_addr];
if (!slot.key) {
slot.key = old_entry.key;
slot.value = std::move(old_entry.value);
done = true;
break;
}
}
ASSERT(done);
}
}
m_entries = std::move(new_entries);
m_next_resize = kMaxUsed * m_entries.size();
}
namespace {
/*!

View File

@ -55,6 +55,7 @@
#include "common/common_types.h"
#include "common/util/Assert.h"
#include "common/util/crc32.h"
namespace goos {
@ -456,23 +457,111 @@ class PairObject : public HeapObject {
~PairObject() = default;
};
class EnvironmentMap {
template <typename T>
class InternedPtrMap {
public:
EnvironmentMap(const EnvironmentMap&) = delete;
EnvironmentMap& operator=(const EnvironmentMap&) = delete;
EnvironmentMap();
Object* lookup(InternedSymbolPtr ptr);
void set(InternedSymbolPtr ptr, const Object& obj);
void clear();
InternedPtrMap(const InternedPtrMap&) = delete;
InternedPtrMap& operator=(const InternedPtrMap&) = delete;
InternedPtrMap() { clear(); }
T* lookup(InternedSymbolPtr str) {
if (m_entries.size() < 10) {
for (auto& e : m_entries) {
if (e.key == str.name_ptr) {
return &e.value;
}
}
return nullptr;
}
u32 hash = crc32((const u8*)&str.name_ptr, sizeof(const char*));
// probe
for (u32 i = 0; i < m_entries.size(); i++) {
u32 slot_addr = (hash + i) & m_mask;
auto& slot = m_entries[slot_addr];
if (!slot.key) {
return nullptr;
} else {
if (slot.key != str.name_ptr) {
continue; // bad hash
}
return &slot.value;
}
}
// should be impossible to reach.
ASSERT_NOT_REACHED();
}
void set(InternedSymbolPtr ptr, const T& obj) {
u32 hash = crc32((const u8*)&ptr.name_ptr, sizeof(const char*));
// probe
for (u32 i = 0; i < m_entries.size(); i++) {
u32 slot_addr = (hash + i) & m_mask;
auto& slot = m_entries[slot_addr];
if (!slot.key) {
// not found, insert!
slot.key = ptr.name_ptr;
slot.value = obj;
m_used_entries++;
if (m_used_entries >= m_next_resize) {
resize();
}
return;
} else {
if (slot.key == ptr.name_ptr) {
slot.value = obj;
return;
}
}
}
// should be impossible to reach.
ASSERT_NOT_REACHED();
}
void clear() {
m_entries.clear();
m_power_of_two_size = 3; // 2 ^ 3 = 8
m_entries.resize(8);
m_used_entries = 0;
m_next_resize = (m_entries.size() * kMaxUsed);
m_mask = 0b111;
}
private:
struct Entry {
const char* key = nullptr;
Object value;
T value;
};
std::vector<Entry> m_entries;
void resize();
void resize() {
m_power_of_two_size++;
m_mask = (1U << m_power_of_two_size) - 1;
std::vector<Entry> new_entries(m_entries.size() * 2);
for (const auto& old_entry : m_entries) {
if (old_entry.key) {
bool done = false;
u32 hash = crc32((const u8*)&old_entry.key, sizeof(const char*));
for (u32 i = 0; i < new_entries.size(); i++) {
u32 slot_addr = (hash + i) & m_mask;
auto& slot = new_entries[slot_addr];
if (!slot.key) {
slot.key = old_entry.key;
slot.value = std::move(old_entry.value);
done = true;
break;
}
}
ASSERT(done);
}
}
m_entries = std::move(new_entries);
m_next_resize = kMaxUsed * m_entries.size();
}
int m_power_of_two_size = 0;
int m_used_entries = 0;
int m_next_resize = 0;
@ -480,6 +569,8 @@ class EnvironmentMap {
static constexpr float kMaxUsed = 0.7;
};
using EnvironmentMap = InternedPtrMap<Object>;
class EnvironmentObject : public HeapObject {
public:
std::string name;

View File

@ -84,12 +84,10 @@ double get_float(const goos::Object& obj) {
throw std::runtime_error(obj.print() + " was supposed to be an number, but isn't");
}
void add_field(
StructureType* structure,
TypeSystem* ts,
const goos::Object& def,
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>&
constants) {
void add_field(StructureType* structure,
TypeSystem* ts,
const goos::Object& def,
goos::EnvironmentMap* constants) {
auto rest = &def;
auto name = symbol_string(car(rest));
@ -113,9 +111,8 @@ void add_field(
if (car(rest).is_int()) {
array_size = car(rest).integer_obj.value;
rest = cdr(rest);
} else if (car(rest).is_symbol() &&
constants.find((car(rest)).as_symbol()) != constants.end()) {
array_size = get_int(constants[(car(rest)).as_symbol()]);
} else if (car(rest).is_symbol() && constants && constants->lookup((car(rest)).as_symbol())) {
array_size = get_int(*constants->lookup((car(rest)).as_symbol()));
rest = cdr(rest);
}
@ -543,13 +540,11 @@ void declare_state(Type* type,
});
}
StructureDefResult parse_structure_def(
StructureType* type,
TypeSystem* ts,
const goos::Object& fields,
const goos::Object& options,
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>&
constants) {
StructureDefResult parse_structure_def(StructureType* type,
TypeSystem* ts,
const goos::Object& fields,
const goos::Object& options,
goos::EnvironmentMap* constants) {
StructureDefResult result;
for_each_in_list(fields, [&](const goos::Object& o) { add_field(type, ts, o, constants); });
TypeFlags flags;
@ -811,18 +806,11 @@ TypeSpec parse_typespec(const TypeSystem* type_system, const goos::Object& src)
return {};
}
DeftypeResult parse_deftype(
const goos::Object& deftype,
TypeSystem* ts,
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>*
constants) {
DeftypeResult parse_deftype(const goos::Object& deftype,
TypeSystem* ts,
goos::EnvironmentMap* constants) {
DefinitionMetadata symbol_metadata;
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>
no_consts;
auto& constants_to_use = no_consts;
if (constants != nullptr) {
constants_to_use = *constants;
}
goos::EnvironmentMap no_consts;
auto iter = &deftype;
@ -861,8 +849,7 @@ DeftypeResult parse_deftype(
}
new_type->inherit(pto);
ts->forward_declare_type_as(name, pto->get_name());
auto sr =
parse_structure_def(new_type.get(), ts, field_list_obj, options_obj, constants_to_use);
auto sr = parse_structure_def(new_type.get(), ts, field_list_obj, options_obj, constants);
result.flags = sr.flags;
result.create_runtime_type = sr.generate_runtime_type;
structure_result = sr;
@ -891,8 +878,7 @@ DeftypeResult parse_deftype(
ASSERT(pto);
new_type->inherit(pto);
ts->forward_declare_type_as(name, pto->get_name());
auto sr =
parse_structure_def(new_type.get(), ts, field_list_obj, options_obj, constants_to_use);
auto sr = parse_structure_def(new_type.get(), ts, field_list_obj, options_obj, constants);
result.flags = sr.flags;
result.create_runtime_type = sr.generate_runtime_type;
structure_result = sr;

View File

@ -17,9 +17,7 @@ struct DeftypeResult {
bool create_runtime_type = true;
};
DeftypeResult parse_deftype(
const goos::Object& deftype,
TypeSystem* ts,
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>*
constants = nullptr);
DeftypeResult parse_deftype(const goos::Object& deftype,
TypeSystem* ts,
goos::EnvironmentMap* constants = nullptr);
TypeSpec parse_typespec(const TypeSystem* type_system, const goos::Object& src);

View File

@ -1,3 +1,5 @@
#pragma once
#include <cstdlib>
#include "common/common_types.h"

View File

@ -125,10 +125,8 @@ class Compiler {
// TODO - this should be able to be removed, these are stored in `m_symbol_info`
std::unordered_map<std::string, goos::ArgumentSpec> m_macro_specs;
// TODO - this should be able to be removed, these are stored in `m_symbol_info`
std::unordered_map<goos::InternedSymbolPtr, TypeSpec, goos::InternedSymbolPtr::hash>
m_symbol_types;
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>
m_global_constants;
goos::InternedPtrMap<TypeSpec> m_symbol_types;
goos::InternedPtrMap<goos::Object> m_global_constants;
std::unordered_map<goos::InternedSymbolPtr, InlineableFunction, goos::InternedSymbolPtr::hash>
m_inlineable_functions;
CompilerSettings m_settings;

View File

@ -314,7 +314,7 @@ bool Compiler::is_local_symbol(const goos::Object& obj, Env* env) {
}
// check global constants
if (m_global_constants.find(obj.as_symbol()) != m_global_constants.end()) {
if (m_global_constants.lookup(obj.as_symbol())) {
return true;
}

View File

@ -219,12 +219,11 @@ Val* Compiler::compile_asm_load_sym(const goos::Object& form, const goos::Object
form, args, {{}, {goos::ObjectType::SYMBOL}},
{{"sext", {false, goos::ObjectType::SYMBOL}}, {"color", {false, goos::ObjectType::SYMBOL}}});
auto& sym_name = args.unnamed.at(1).as_symbol();
auto sym_kv = m_symbol_types.find(sym_name);
if (sym_kv == m_symbol_types.end()) {
const auto* sym_ts = m_symbol_types.lookup(sym_name);
if (!sym_ts) {
throw_compiler_error(form, "Cannot find a symbol named {}.", sym_name.name_ptr);
}
auto ts = sym_kv->second;
bool sext = m_ts.lookup_type(ts)->get_load_signed();
bool sext = m_ts.lookup_type(*sym_ts)->get_load_signed();
if (args.has_named("sext")) {
sext = get_true_or_false(form, args.named.at("sext"));
}

View File

@ -388,13 +388,13 @@ SymbolVal* Compiler::compile_get_sym_obj(const std::string& name, Env* env) {
Val* Compiler::compile_get_symbol_value(const goos::Object& form,
const std::string& name,
Env* env) {
auto existing_symbol = m_symbol_types.find(m_goos.intern_ptr(name));
if (existing_symbol == m_symbol_types.end()) {
auto existing_symbol = m_symbol_types.lookup(m_goos.intern_ptr(name));
if (!existing_symbol) {
throw_compiler_error(
form, "The symbol {} was looked up as a global variable, but it does not exist.", name);
}
auto ts = existing_symbol->second;
const auto& ts = *existing_symbol;
auto sext = m_ts.lookup_type_allow_partial_def(ts)->get_load_signed();
auto fe = env->function_env();
auto sym = fe->alloc_val<SymbolVal>(name, m_ts.make_typespec("symbol"));
@ -431,20 +431,20 @@ Val* Compiler::compile_symbol(const goos::Object& form, Env* env) {
return lexical;
}
auto global_constant = m_global_constants.find(form.as_symbol());
auto existing_symbol = m_symbol_types.find(form.as_symbol());
auto global_constant = m_global_constants.lookup(form.as_symbol());
auto existing_symbol = m_symbol_types.lookup(form.as_symbol());
// see if it's a constant
if (global_constant != m_global_constants.end()) {
if (global_constant) {
// check there is no symbol with the same name
if (existing_symbol != m_symbol_types.end()) {
if (existing_symbol) {
throw_compiler_error(form,
"Ambiguous symbol: {} is both a global variable and a constant and it "
"is not clear which should be used here.");
}
// got a global constant
return compile_error_guard(global_constant->second, env);
return compile_error_guard(*global_constant, env);
}
// none of those, so get a global symbol.

View File

@ -362,7 +362,7 @@ std::string Compiler::make_symbol_info_description(const symbol_info::SymbolInfo
switch (info->m_kind) {
case symbol_info::Kind::GLOBAL_VAR:
return fmt::format("[Global Variable] Type: {} Defined: {}",
m_symbol_types.at(m_goos.intern_ptr(info->m_name)).print(),
m_symbol_types.lookup(m_goos.intern_ptr(info->m_name))->print(),
m_goos.reader.db.get_info_for(info->m_def_form));
case symbol_info::Kind::LANGUAGE_BUILTIN:
return fmt::format("[Built-in Form] {}\n", info->m_name);
@ -379,7 +379,8 @@ std::string Compiler::make_symbol_info_description(const symbol_info::SymbolInfo
case symbol_info::Kind::CONSTANT:
return fmt::format(
"[Constant] Name: {} Value: {} Defined: {}", info->m_name,
m_global_constants.at(m_goos.reader.symbolTable.intern(info->m_name.c_str())).print(),
m_global_constants.lookup(m_goos.reader.symbolTable.intern(info->m_name.c_str()))
->print(),
m_goos.reader.db.get_info_for(info->m_def_form));
case symbol_info::Kind::FUNCTION:
return fmt::format("[Function] Name: {} Defined: {}", info->m_name,
@ -615,9 +616,9 @@ std::vector<symbol_info::SymbolInfo*> Compiler::lookup_exact_name_info(
}
std::optional<TypeSpec> Compiler::lookup_typespec(const std::string& symbol_name) {
const auto& it = m_symbol_types.find(m_goos.intern_ptr(symbol_name));
if (it != m_symbol_types.end()) {
return it->second;
const auto it = m_symbol_types.lookup(m_goos.intern_ptr(symbol_name));
if (it) {
return *it;
}
return {};
}
@ -686,7 +687,7 @@ Compiler::generate_per_file_symbol_info() {
if (sym_info->m_kind == symbol_info::Kind::CONSTANT) {
var.type = "unknown"; // Unfortunately, constants are not properly typed
} else {
var.type = m_symbol_types.at(m_goos.intern_ptr(var.name)).base_type();
var.type = m_symbol_types.lookup(m_goos.intern_ptr(var.name))->base_type();
}
var.def_location = def_loc;
if (sym_info->m_kind == symbol_info::Kind::GLOBAL_VAR) {
@ -701,8 +702,8 @@ Compiler::generate_per_file_symbol_info() {
func.def_location = def_loc;
func.args = Docs::get_args_from_docstring(sym_info->m_args, func.description);
// The last arg in the typespec is the return type
const auto& func_type = m_symbol_types.at(m_goos.intern_ptr(func.name));
func.return_type = func_type.last_arg().base_type();
const auto func_type = m_symbol_types.lookup(m_goos.intern_ptr(func.name));
func.return_type = func_type->last_arg().base_type();
file_doc.functions.push_back(func);
} else if (sym_info->m_kind == symbol_info::Kind::TYPE) {
Docs::TypeDocumentation type;

View File

@ -187,13 +187,13 @@ Compiler::ConstPropResult Compiler::constant_propagation_dispatch(const goos::Ob
}
// it can either be a global or symbol
const auto& global_constant = m_global_constants.find(expanded.as_symbol());
const auto& existing_symbol = m_symbol_types.find(expanded.as_symbol());
const auto* global_constant = m_global_constants.lookup(expanded.as_symbol());
const auto* existing_symbol = m_symbol_types.lookup(expanded.as_symbol());
// see if it's a constant
if (global_constant != m_global_constants.end()) {
if (global_constant) {
// check there is no symbol with the same name, this is likely a bug and complain.
if (existing_symbol != m_symbol_types.end()) {
if (existing_symbol) {
throw_compiler_error(
code,
"Ambiguous symbol: {} is both a global variable and a constant and it "
@ -201,7 +201,7 @@ Compiler::ConstPropResult Compiler::constant_propagation_dispatch(const goos::Ob
}
// got a global constant
return try_constant_propagation(global_constant->second, env);
return try_constant_propagation(*global_constant, env);
} else {
// return to the compiler, we can't figure it out.
return {expanded, true};

View File

@ -24,11 +24,11 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest
auto& val = args.unnamed.at(1);
// check we aren't duplicated a name as both a symbol and global constant
auto global_constant = m_global_constants.find(sym.as_symbol());
if (global_constant != m_global_constants.end()) {
auto global_constant = m_global_constants.lookup(sym.as_symbol());
if (global_constant) {
throw_compiler_error(
form, "Cannot define a symbol named {}, it already exists as a global constant (value {}).",
sym.print(), global_constant->second.print());
sym.print(), global_constant->print());
}
auto fe = env->function_env();
@ -66,16 +66,16 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest
throw_compiler_error(form, "Cannot define {} because it cannot be set.", sym_val->print());
}
auto existing_type = m_symbol_types.find(sym.as_symbol());
if (existing_type == m_symbol_types.end()) {
m_symbol_types[sym.as_symbol()] = in_gpr->type();
auto existing_type = m_symbol_types.lookup(sym.as_symbol());
if (!existing_type) {
m_symbol_types.set(sym.as_symbol(), in_gpr->type());
} else {
bool do_typecheck = true;
if (args.has_named("no-typecheck")) {
do_typecheck = !get_true_or_false(form, args.named.at("no-typecheck"));
}
if (do_typecheck) {
typecheck(form, existing_type->second, in_gpr->type(),
typecheck(form, *existing_type, in_gpr->type(),
fmt::format("define on existing symbol {}", sym.as_symbol().name_ptr));
}
}
@ -107,27 +107,26 @@ Val* Compiler::compile_define_extern(const goos::Object& form, const goos::Objec
auto new_type = parse_typespec(typespec, env);
auto existing_type = m_symbol_types.find(sym.as_symbol());
auto existing_type = m_symbol_types.lookup(sym.as_symbol());
// symbol already declared, and doesn't match existing definition. do more checks...
if (existing_type != m_symbol_types.end() && existing_type->second != new_type) {
if (existing_type && *existing_type != new_type) {
if (m_allow_inconsistent_definition_symbols.find(symbol_string(sym)) ==
m_allow_inconsistent_definition_symbols.end()) {
// throw if we have throws enabled, and new definition is NOT just more generic
// (that case is fine in goal)
if (!m_ts.tc(new_type, existing_type->second) && m_throw_on_define_extern_redefinition) {
if (!m_ts.tc(new_type, *existing_type) && m_throw_on_define_extern_redefinition) {
throw_compiler_error(form,
"define-extern would redefine the type of symbol {} from {} to {}.",
symbol_string(sym), existing_type->second.print(), new_type.print());
symbol_string(sym), existing_type->print(), new_type.print());
} else {
print_compiler_warning(
"define-extern has redefined the type of symbol {}\npreviously: {}\nnow: {}\n",
symbol_string(sym).c_str(), existing_type->second.print().c_str(),
new_type.print().c_str());
symbol_string(sym).c_str(), existing_type->print().c_str(), new_type.print().c_str());
}
}
}
m_symbol_types[sym.as_symbol()] = new_type;
m_symbol_types.set(sym.as_symbol(), new_type);
m_symbol_info.add_fwd_dec(symbol_string(sym), form);
return get_none();
}

View File

@ -346,8 +346,7 @@ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* en
if (uneval_head.as_symbol() == "inspect" || uneval_head.as_symbol() == "print") {
is_method_call = true;
} else {
if (is_local_symbol(uneval_head, env) ||
m_symbol_types.find(uneval_head.as_symbol()) != m_symbol_types.end()) {
if (is_local_symbol(uneval_head, env) || m_symbol_types.lookup(uneval_head.as_symbol())) {
// the local environment (mlets, lexicals, constants, globals) defines this symbol.
// this will "win" over a method name lookup, so we should compile as normal
head = compile_error_guard(args.unnamed.front(), env);

View File

@ -196,19 +196,19 @@ Val* Compiler::compile_define_constant(const goos::Object& form,
// GOAL constant
if (goal) {
if (m_symbol_types.find(sym) != m_symbol_types.end()) {
if (m_symbol_types.lookup(sym)) {
throw_compiler_error(form,
"Cannot define {} as a constant because "
"it is already the name of a symbol of type {}",
sym.name_ptr, m_symbol_types.at(sym).print());
sym.name_ptr, m_symbol_types.lookup(sym)->print());
}
auto existing = m_global_constants.find(sym);
if (existing != m_global_constants.end() && existing->second != value) {
auto existing = m_global_constants.lookup(sym);
if (existing && *existing != value) {
print_compiler_warning("Constant {} has been redefined {} -> {}", sym.name_ptr,
existing->second.print(), value.print());
existing->print(), value.print());
}
m_global_constants[sym] = value;
m_global_constants.set(sym, value);
}
// GOOS constant

View File

@ -98,10 +98,10 @@ Val* Compiler::compile_define_state_hook(const goos::Object& form,
}
auto& state_name = args.unnamed.at(0).as_symbol();
auto existing_var = m_symbol_types.find(state_name);
auto existing_var = m_symbol_types.lookup(state_name);
TypeSpec type_to_use;
if (existing_var == m_symbol_types.end()) {
if (!existing_var) {
// we're a new state. we must have a type.
if (!state_type) {
throw_compiler_error(form,
@ -110,11 +110,11 @@ Val* Compiler::compile_define_state_hook(const goos::Object& form,
state_name.name_ptr);
}
type_to_use = *state_type;
m_symbol_types[state_name] = *state_type;
m_symbol_types.set(state_name, *state_type);
} else {
type_to_use = existing_var->second;
type_to_use = *existing_var;
if (state_type) {
typecheck(form, existing_var->second, *state_type,
typecheck(form, *existing_var, *state_type,
fmt::format("type of state {}", state_name.name_ptr));
}
}

View File

@ -700,10 +700,10 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env
}
// as a constant
auto kv = m_global_constants.find(form.as_symbol());
if (kv != m_global_constants.end()) {
auto kv = m_global_constants.lookup(form.as_symbol());
if (kv) {
// expand constant and compile again.
return compile_static(kv->second, env);
return compile_static(*kv, env);
} else {
throw_compiler_error(form, "The symbol {} could not be evaluated at compile time",
form.print());

View File

@ -386,33 +386,32 @@ Val* Compiler::compile_deftype(const goos::Object& form, const goos::Object& res
auto result = parse_deftype(rest, &m_ts, &m_global_constants);
// look up the type name
auto kv = m_symbol_types.find(m_goos.intern_ptr(result.type.base_type()));
if (kv != m_symbol_types.end() && kv->second.base_type() != "type") {
auto kv = m_symbol_types.lookup(m_goos.intern_ptr(result.type.base_type()));
if (kv && kv->base_type() != "type") {
// we already have something that's not a type with the same name, this is bad.
lg::print("[Warning] deftype will redefine {} from {} to a type.\n", result.type.base_type(),
kv->second.print());
kv->print());
}
// remember that this is a type
m_symbol_types[m_goos.intern_ptr(result.type.base_type())] = m_ts.make_typespec("type");
m_symbol_types.set(m_goos.intern_ptr(result.type.base_type()), m_ts.make_typespec("type"));
// add declared states
for (auto& state : result.type_info->get_states_declared_for_type()) {
auto interned_state_first = m_goos.intern_ptr(state.first);
auto existing_type = m_symbol_types.find(interned_state_first);
if (existing_type != m_symbol_types.end() && existing_type->second != state.second) {
auto existing_type = m_symbol_types.lookup(interned_state_first);
if (existing_type && *existing_type != state.second) {
if (m_throw_on_define_extern_redefinition) {
throw_compiler_error(form, "deftype would redefine the type of state {} from {} to {}.",
state.first, existing_type->second.print(), state.second.print());
state.first, existing_type->print(), state.second.print());
} else {
print_compiler_warning(
"[Warning] deftype has redefined the type of state {}\npreviously: {}\nnow: "
"{}\n",
state.first.c_str(), existing_type->second.print().c_str(),
state.second.print().c_str());
state.first.c_str(), existing_type->print().c_str(), state.second.print().c_str());
}
}
m_symbol_types[interned_state_first] = state.second;
m_symbol_types.set(interned_state_first, state.second);
m_symbol_info.add_fwd_dec(state.first, form);
}
@ -1444,12 +1443,12 @@ Val* Compiler::compile_declare_type(const goos::Object& form, const goos::Object
m_ts.forward_declare_type_as(type_name.name_ptr, kind);
auto existing_type = m_symbol_types.find(type_name);
if (existing_type != m_symbol_types.end() && existing_type->second != TypeSpec("type")) {
auto existing_type = m_symbol_types.lookup(type_name);
if (existing_type && *existing_type != TypeSpec("type")) {
throw_compiler_error(form, "Cannot forward declare {} as a type: it is already a {}",
type_name.name_ptr, existing_type->second.print());
type_name.name_ptr, existing_type->print());
}
m_symbol_types[type_name] = TypeSpec("type");
m_symbol_types.set(type_name, TypeSpec("type"));
return get_none();
}

View File

@ -239,7 +239,7 @@ void SymbolInfoMap::add_builtin(const std::string& name, const std::string& docs
void SymbolInfoMap::add_method(const std::string& method_name,
const std::vector<GoalArg>& args,
const MethodInfo& method_info,
const goos::Object& defining_form) {
const goos::Object& /*defining_form*/) {
SymbolInfo info = {
.m_kind = Kind::METHOD,
.m_name = method_name,