diff options
| -rw-r--r-- | boot/name_analysis.cc | 2 | ||||
| -rw-r--r-- | boot/type_check.cc | 28 | ||||
| -rw-r--r-- | include/elna/boot/type_check.h | 1 | ||||
| -rw-r--r-- | testsuite/compilable/const_element_array.elna | 9 | ||||
| -rw-r--r-- | testsuite/compilable/const_extern.elna | 5 | ||||
| -rw-r--r-- | testsuite/fail_compilation/assign_const_element.elna | 11 |
6 files changed, 55 insertions, 1 deletions
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index 70b9031..3c4c6f8 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -420,7 +420,7 @@ namespace elna::boot non_constant_expression_error::initializer{ extract_identifiers(declaration->identifiers) }); } } - else if (resolve_aliases(variable_type).get<constant_type>() != nullptr) + else if (!declaration->is_extern && resolve_aliases(variable_type).get<constant_type>() != nullptr) { auto position_span = source_position(declaration->identifiers.front().id().position().start(), declaration->identifiers.back().id().position().end()); diff --git a/boot/type_check.cc b/boot/type_check.cc index 068d958..74c8176 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -513,12 +513,40 @@ namespace elna::boot return verdict::pass; } + assign_check::verdict assign_check::check_array_conversion() const + { + auto assignee_array = ctx.resolved_assignee.get<array_type>(); + auto assignment_array = ctx.resolved_assignment.get<array_type>(); + + if (assignee_array == nullptr || assignment_array == nullptr + || assignee_array->size != assignment_array->size) + { + return verdict::pass; + } + auto assignee_element_const = resolve_aliases(assignee_array->base).get<constant_type>(); + auto assignment_element_const = resolve_aliases(assignment_array->base).get<constant_type>(); + + // An array is copied by value, so const can be added to the element type, + // but not removed. Writing to such an array is rejected on the lvalue. + if (assignee_element_const != nullptr + && assignee_element_const->unqualified == assignment_array->base) + { + return verdict::accept; + } + if (assignment_element_const != nullptr && assignee_element_const == nullptr) + { + return verdict::reject; + } + return verdict::pass; + } + bool assign_check::run() { auto const assign_handlers = { &assign_check::guard_const_laundering, &assign_check::check_exact_match, &assign_check::check_slice_conversion, + &assign_check::check_array_conversion, &assign_check::check_pointer_hatch, &assign_check::check_pointer_conversion }; diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h index 37a4fca..e2f5cc9 100644 --- a/include/elna/boot/type_check.h +++ b/include/elna/boot/type_check.h @@ -189,6 +189,7 @@ namespace elna::boot verdict check_pointer_hatch() const; verdict check_pointer_conversion() const; verdict check_slice_conversion() const; + verdict check_array_conversion() const; bool run(); }; diff --git a/testsuite/compilable/const_element_array.elna b/testsuite/compilable/const_element_array.elna new file mode 100644 index 0000000..a812d23 --- /dev/null +++ b/testsuite/compilable/const_element_array.elna @@ -0,0 +1,9 @@ +type + CI = const Int + +var + a: [3]CI := [1, 2, 3] + b: [3]CI + +begin +end. diff --git a/testsuite/compilable/const_extern.elna b/testsuite/compilable/const_extern.elna new file mode 100644 index 0000000..8df801e --- /dev/null +++ b/testsuite/compilable/const_extern.elna @@ -0,0 +1,5 @@ +var + errno_like: const Int := extern + +begin +end. diff --git a/testsuite/fail_compilation/assign_const_element.elna b/testsuite/fail_compilation/assign_const_element.elna new file mode 100644 index 0000000..9b9c341 --- /dev/null +++ b/testsuite/fail_compilation/assign_const_element.elna @@ -0,0 +1,11 @@ +type + CI = const Int + +proc f() +var + a: [3]CI := [1, 2, 3] +begin + a[1] := 6 (* @Error Cannot assign to a value of type 'CI', because it is constant or contains constant members *) +return + +end. |
