From d4b7f5e52a33f2d15aafca7f1b040f3f2821fd0c Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Thu, 8 Oct 2026 01:29:37 +0200 Subject: Move record constructor type into the braces --- boot/ast.cc | 28 +++++++++------------- boot/name_analysis.cc | 17 ++----------- boot/parser.yy | 18 ++++++-------- gcc/gcc/elna-generic.cc | 15 +++--------- include/elna/boot/ast.h | 16 ++++--------- .../fail_compilation/assign_const_member.elna | 4 ++-- .../fail_compilation/assign_member_of_const.elna | 2 +- .../record_base_constructor_type_mismatch.elna | 2 +- testsuite/runnable/aggregate_argument.elna | 2 +- testsuite/runnable/aggregate_equality.elna | 2 +- testsuite/runnable/case_record.elna | 6 ++--- testsuite/runnable/generic_constructor.elna | 2 +- testsuite/runnable/record_base_constructor.elna | 2 +- testsuite/runnable/record_construction.elna | 2 +- testsuite/runnable/return_aggregate.elna | 4 ++-- testsuite/runnable/two_fields_same_type.elna | 2 +- 16 files changed, 43 insertions(+), 81 deletions(-) diff --git a/boot/ast.cc b/boot/ast.cc index dc643fe..d698cd4 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -423,6 +423,7 @@ namespace elna::boot void walking_visitor::visit(record_constructor_expression *expression) { + expression->record_type().accept(this); for (const field_initializer& initializer : expression->field_initializers) { initializer.value().accept(this); @@ -844,36 +845,29 @@ namespace elna::boot } record_constructor_expression::record_constructor_expression(const source_position position, - identifier&& type_name, - std::vector&& field_initializers) - : node(position), type_name(std::move(type_name)), field_initializers(std::move(field_initializers)) + type_expression *record_type, std::vector&& field_initializers) + : node(position), m_record_type(record_type), field_initializers(std::move(field_initializers)) { } - record_constructor_expression::record_constructor_expression(const source_position position, - identifier&& type_name, std::vector&& arguments, - std::vector&& field_initializers) - : node(position), type_name(std::move(type_name)), - field_initializers(std::move(field_initializers)), arguments(std::move(arguments)) + void record_constructor_expression::accept(parser_visitor *visitor) { + visitor->visit(this); } - record_constructor_expression::~record_constructor_expression() + record_constructor_expression *record_constructor_expression::is_record_constructor() { - for (const type_expression *argument : this->arguments) - { - delete argument; - } + return this; } - void record_constructor_expression::accept(parser_visitor *visitor) + type_expression& record_constructor_expression::record_type() { - visitor->visit(this); + return *this->m_record_type; } - record_constructor_expression *record_constructor_expression::is_record_constructor() + record_constructor_expression::~record_constructor_expression() { - return this; + delete this->m_record_type; } array_constructor_expression::array_constructor_expression(const source_position position, diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index ff5f6bc..5ad2a75 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -918,21 +918,8 @@ namespace elna::boot void resolving_visitor::visit(record_constructor_expression *expression) { - if (const auto type_symbol = this->bag.lookup(expression->type_name.name())) - { - if (const auto type_info = type_symbol->is_type()) - { - expression->type_decoration = expression->arguments.empty() - ? type_info->symbol - : type(std::make_shared(type_info->symbol, - resolve_arguments(expression->arguments))); - } - } - else - { - add_error(expression->type_name.position(), - expression->type_name.name(), symbol_declaration_error::kind::undeclared_type); - } + expression->type_decoration = resolve_type(expression->record_type()); + for (const field_initializer& initializer : expression->field_initializers) { initializer.value().accept(this); diff --git a/boot/parser.yy b/boot/parser.yy index e8c3590..f416d57 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -424,14 +424,9 @@ simple_expression: } | call_expression { $$ = $1; } | "(" expression ")" { $$ = $2; } - | name_reference "{" field_initializers "}" + | "{" type_expression field_initializers "}" { - boot::named_expression *reference = $1; - - $$ = new boot::record_constructor_expression(boot::make_position(@$), - boot::identifier(reference->name, reference->position()), - std::move(reference->arguments), $3); - delete reference; + $$ = new boot::record_constructor_expression(boot::make_position(@$), $2, $3); } | "[" required_expressions "]" { @@ -644,12 +639,13 @@ field_declarations: field_initializer: identifier ":" expression { $$ = std::make_unique(std::move(*$1), $3); } field_initializers: - field_initializer "," field_initializers + ";" field_initializer { $$.push_back(std::move(*$2)); } + | field_initializers "," field_initializer { - $$ = $3; - $$.emplace($$.cbegin(), std::move(*$1)); + $$ = $1; + $$.push_back(std::move(*$3)); } - | field_initializer { $$.push_back(std::move(*$1)); } + | %empty {} array_type_expression: "[" expression "]" type_expression { $$ = new boot::array_type_expression(boot::make_position(@$), $4, $2); } diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc index 77ff61f..bb93270 100644 --- a/gcc/gcc/elna-generic.cc +++ b/gcc/gcc/elna-generic.cc @@ -248,14 +248,9 @@ namespace elna::gcc void generic_visitor::visit(boot::record_constructor_expression *expression) { - tree type_decl = this->symbols->lookup(expression->type_name.name()); + tree record_type = get_inner_alias(expression->type_decoration, this->symbols); + gcc_assert(TREE_CODE(record_type) == RECORD_TYPE); - if (type_decl == NULL_TREE) - { - this->current_expression = error_mark_node; - return; - } - tree record_type = TREE_TYPE(type_decl); vec *tree_arguments = nullptr; for (const boot::field_initializer& initializer : expression->field_initializers) @@ -271,12 +266,8 @@ namespace elna::gcc void generic_visitor::visit(boot::array_constructor_expression *expression) { tree array_type = get_inner_alias(expression->type_decoration, this->symbols); + gcc_assert(TREE_CODE(array_type) == ARRAY_TYPE); - if (TREE_CODE(array_type) != ARRAY_TYPE) - { - this->current_expression = error_mark_node; - return; - } tree domain = TYPE_DOMAIN(array_type); tree index = TYPE_MIN_VALUE(domain); vec *tree_arguments = nullptr; diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index c3b43bb..35cfc8d 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -559,24 +559,18 @@ namespace elna::boot class record_constructor_expression : public expression { + type_expression *m_record_type; + public: - const identifier type_name; const std::vector field_initializers; - /** - * Type arguments naming the instantiation being constructed. Empty - * when no argument list was written. - */ - const std::vector arguments; record_constructor_expression(const source_position position, - identifier&& type_name, - std::vector&& field_initializers); - record_constructor_expression(const source_position position, - identifier&& type_name, std::vector&& arguments, - std::vector&& field_initializers); + type_expression *record_type, std::vector&& field_initializers); ~record_constructor_expression() override; void accept(parser_visitor *visitor) override; record_constructor_expression *is_record_constructor() override; + + type_expression& record_type(); }; class array_constructor_expression : public expression diff --git a/testsuite/fail_compilation/assign_const_member.elna b/testsuite/fail_compilation/assign_const_member.elna index a603729..13e9e40 100644 --- a/testsuite/fail_compilation/assign_const_member.elna +++ b/testsuite/fail_compilation/assign_const_member.elna @@ -7,8 +7,8 @@ type proc f() var - r1: R := R{ x: 5 } - r2: R := R{ x: 5 } + r1: R := { R; x: 5 } + r2: R := { R; x: 5 } begin r1 := r2 (* @Error Cannot assign to a value of type 'R', because it is constant or contains constant members *) return diff --git a/testsuite/fail_compilation/assign_member_of_const.elna b/testsuite/fail_compilation/assign_member_of_const.elna index efdf67b..44fb566 100644 --- a/testsuite/fail_compilation/assign_member_of_const.elna +++ b/testsuite/fail_compilation/assign_member_of_const.elna @@ -7,7 +7,7 @@ type proc f() var - r: const R := R{ x: 5 } + r: const R := { R; x: 5 } begin r.x := 6 (* @Error Cannot assign to a value of type 'const Int', because it is constant or contains constant members *) return diff --git a/testsuite/fail_compilation/record_base_constructor_type_mismatch.elna b/testsuite/fail_compilation/record_base_constructor_type_mismatch.elna index d7a8419..27a652c 100644 --- a/testsuite/fail_compilation/record_base_constructor_type_mismatch.elna +++ b/testsuite/fail_compilation/record_base_constructor_type_mismatch.elna @@ -11,5 +11,5 @@ var c: Child begin - c := Child{a: "wrong", b: 9} (* @Error Expected type 'Int', but got '\[\]const Word8' *) + c := { Child; a: "wrong", b: 9 } (* @Error Expected type 'Int', but got '\[\]const Word8' *) end. diff --git a/testsuite/runnable/aggregate_argument.elna b/testsuite/runnable/aggregate_argument.elna index 7ae4947..edd9529 100644 --- a/testsuite/runnable/aggregate_argument.elna +++ b/testsuite/runnable/aggregate_argument.elna @@ -9,5 +9,5 @@ proc f(r: R) -> Bool return r.a = 1 & r.b = 2 begin - assert(f(R{a: 1, b: 2})) + assert(f({ R; a: 1, b: 2 })) end. diff --git a/testsuite/runnable/aggregate_equality.elna b/testsuite/runnable/aggregate_equality.elna index c9601f9..b3e0646 100644 --- a/testsuite/runnable/aggregate_equality.elna +++ b/testsuite/runnable/aggregate_equality.elna @@ -6,7 +6,7 @@ type end proc f() -> Bool -return R{a: 1, b: 2} = R{a: 1, b: 2} +return { R; a: 1, b: 2 } = { R; a: 1, b: 2 } begin assert(f()) diff --git a/testsuite/runnable/case_record.elna b/testsuite/runnable/case_record.elna index db8a6ff..13d6add 100644 --- a/testsuite/runnable/case_record.elna +++ b/testsuite/runnable/case_record.elna @@ -6,12 +6,12 @@ type end var - r: R := R{a: 1, b: 2} + r: R := { R; a: 1, b: 2 } begin case r of - R{a: 0, b: 0}: assert(false) - | R{a: 1, b: 2}: assert(true) + { R; a: 0, b: 0 }: assert(false) | + { R; a: 1, b: 2 }: assert(true) else assert(false) end diff --git a/testsuite/runnable/generic_constructor.elna b/testsuite/runnable/generic_constructor.elna index b21cd4a..a67b4f3 100644 --- a/testsuite/runnable/generic_constructor.elna +++ b/testsuite/runnable/generic_constructor.elna @@ -14,7 +14,7 @@ var f: File begin - s := Stack#[File]{ top: 1u, items: @f }; + s := { Stack#[File]; top: 1u, items: @f }; assert(s.top = 1u); assert(s.items = @f) end. diff --git a/testsuite/runnable/record_base_constructor.elna b/testsuite/runnable/record_base_constructor.elna index 80b6802..58e81ca 100644 --- a/testsuite/runnable/record_base_constructor.elna +++ b/testsuite/runnable/record_base_constructor.elna @@ -11,7 +11,7 @@ type end var - g: Grandchild := Grandchild{a: 3, b: 5, c: 7} + g: Grandchild := { Grandchild; a: 3, b: 5, c: 7 } begin assert(g.a = 3); diff --git a/testsuite/runnable/record_construction.elna b/testsuite/runnable/record_construction.elna index 5a3a254..64770de 100644 --- a/testsuite/runnable/record_construction.elna +++ b/testsuite/runnable/record_construction.elna @@ -5,7 +5,7 @@ type end var - r: R := R{x: 1, y: 2} + r: R := { R; x: 1, y: 2 } begin assert(r.x = 1 & r.y = 2) diff --git a/testsuite/runnable/return_aggregate.elna b/testsuite/runnable/return_aggregate.elna index 6959b60..c39823d 100644 --- a/testsuite/runnable/return_aggregate.elna +++ b/testsuite/runnable/return_aggregate.elna @@ -6,8 +6,8 @@ type end proc f() -> R -return R{ a: 1, b: 2 } +return { R; a: 1, b: 2 } begin - assert(f() = R{ a: 1, b: 2 }) + assert(f() = { R; a: 1, b: 2 }) end. diff --git a/testsuite/runnable/two_fields_same_type.elna b/testsuite/runnable/two_fields_same_type.elna index 2b905b6..8f1d4cf 100644 --- a/testsuite/runnable/two_fields_same_type.elna +++ b/testsuite/runnable/two_fields_same_type.elna @@ -6,7 +6,7 @@ type proc f() -> Int var - r: R := R{x: 3, y: 2} + r: R := { R; x: 3, y: 2 } return r.x + r.y begin -- cgit v1.2.3