Store inferred struct field type in the field node itself

This commit is contained in:
Nikita Lisitsa 2026-03-16 12:44:27 +03:00
parent ab028c9d7a
commit 53be7b92df
2 changed files with 17 additions and 24 deletions

View file

@ -22,6 +22,7 @@ namespace pslang::ast
ast::type_ptr type; ast::type_ptr type;
ast::location location; ast::location location;
types::type_ptr inferred_type = nullptr;
field_layout layout = {}; field_layout layout = {};
}; };

View file

@ -30,17 +30,9 @@ namespace pslang::ast
struct struct_data struct struct_data
{ {
struct field_data
{
std::string name;
types::type_ptr type;
};
ast::struct_definition * node; ast::struct_definition * node;
bool layout_being_computed = false; bool layout_being_computed = false;
bool layout_ready = false; bool layout_ready = false;
std::vector<field_data> fields;
}; };
struct scope struct scope
@ -115,11 +107,13 @@ namespace pslang::ast
if (data.layout_ready) if (data.layout_ready)
return; return;
auto & struct_node = *data.node;
data.layout_being_computed = true; data.layout_being_computed = true;
auto & layout = data.node->layout; auto & layout = data.node->layout;
for (std::size_t i = 0; i < data.fields.size(); ++i) for (std::size_t i = 0; i < struct_node.fields.size(); ++i)
{ {
auto field_layout = field_layout_visitor{{}, scopes}.apply(*data.fields[i].type); auto field_layout = field_layout_visitor{{}, scopes}.apply(*struct_node.fields[i].inferred_type);
layout.alignment = std::max(layout.alignment, field_layout.alignment); layout.alignment = std::max(layout.alignment, field_layout.alignment);
layout.size = ((layout.size + field_layout.alignment - 1) / field_layout.alignment) * field_layout.alignment; layout.size = ((layout.size + field_layout.alignment - 1) / field_layout.alignment) * field_layout.alignment;
data.node->fields[i].layout.offset = layout.size; data.node->fields[i].layout.offset = layout.size;
@ -253,20 +247,18 @@ namespace pslang::ast
void apply(return_statement const &) void apply(return_statement const &)
{} {}
void apply(field_definition const & node) void apply(field_definition & node)
{ {
resolve_types(scopes, *node.type); resolve_types(scopes, *node.type);
node.inferred_type = get_type(*node.type);
} }
void apply(struct_definition & node) void apply(struct_definition & node)
{ {
for (auto const & field : node.fields) for (auto & field : node.fields)
apply(field); apply(field);
auto & data = scopes.back().structs[node.name]; scopes.back().structs[node.name].node = &node;
data.node = &node;
for (auto const & field : node.fields)
data.fields.push_back({.name = field.name, .type = get_type(*field.type)});
} }
}; };
@ -574,25 +566,25 @@ namespace pslang::ast
else if (auto named_type = std::get_if<types::named_type>(type.get())) else if (auto named_type = std::get_if<types::named_type>(type.get()))
{ {
auto const & scope = scopes.at(named_type->level); auto const & scope = scopes.at(named_type->level);
auto const & data = scope.structs.at(named_type->name); auto const & struct_node = *scope.structs.at(named_type->name).node;
if (!node.arguments.empty()) if (!node.arguments.empty())
{ {
if (node.arguments.size() != data.fields.size()) if (node.arguments.size() != struct_node.fields.size())
{ {
std::ostringstream os; std::ostringstream os;
os << "Cannot create struct " << named_type->name << ": expected " << data.fields.size() << " arguments, but got " << node.arguments.size(); os << "Cannot create struct " << named_type->name << ": expected " << struct_node.fields.size() << " arguments, but got " << node.arguments.size();
throw type_error(os.str(), node.location); throw type_error(os.str(), node.location);
} }
for (std::size_t i = 0; i < node.arguments.size(); ++i) for (std::size_t i = 0; i < node.arguments.size(); ++i)
{ {
auto arg_type = get_type(*node.arguments[i]); auto arg_type = get_type(*node.arguments[i]);
if (!types::equal(*arg_type, *data.fields[i].type)) if (!types::equal(*arg_type, *struct_node.fields[i].inferred_type))
{ {
std::ostringstream os; std::ostringstream os;
os << "Cannot create struct " << named_type->name << ": argument #" << i << " expected to have type "; os << "Cannot create struct " << named_type->name << ": argument #" << i << " expected to have type ";
types::print(os, *data.fields[i].type); types::print(os, *struct_node.fields[i].inferred_type);
os << " but got type "; os << " but got type ";
types::print(os, *arg_type); types::print(os, *arg_type);
throw type_error(os.str(), node.location); throw type_error(os.str(), node.location);
@ -685,13 +677,13 @@ namespace pslang::ast
throw type_error(os.str(), get_location(*node.object)); throw type_error(os.str(), get_location(*node.object));
} }
auto const & struct_data = scopes.at(named_type->level).structs.at(named_type->name); auto const & struct_node = *scopes.at(named_type->level).structs.at(named_type->name).node;
for (auto const & field : struct_data.fields) for (auto const & field : struct_node.fields)
{ {
if (field.name == node.field_name) if (field.name == node.field_name)
{ {
node.inferred_type = field.type; node.inferred_type = field.inferred_type;
return; return;
} }
} }